]> git.lizzy.rs Git - rust.git/commitdiff
Auto merge of #105160 - nnethercote:rm-Lit-token_lit, r=petrochenkov
authorbors <bors@rust-lang.org>
Mon, 12 Dec 2022 05:16:50 +0000 (05:16 +0000)
committerbors <bors@rust-lang.org>
Mon, 12 Dec 2022 05:16:50 +0000 (05:16 +0000)
Remove `token::Lit` from `ast::MetaItemLit`.

Currently `ast::MetaItemLit` represents the literal kind twice. This PR removes that redundancy. Best reviewed one commit at a time.

r? `@petrochenkov`

1401 files changed:
.github/workflows/ci.yml
.gitmodules
Cargo.lock
Cargo.toml
LICENSES/LLVM-exception.txt [new file with mode: 0644]
compiler/rustc_abi/src/layout.rs
compiler/rustc_abi/src/lib.rs
compiler/rustc_apfloat/src/ieee.rs
compiler/rustc_arena/src/lib.rs
compiler/rustc_ast/src/ast.rs
compiler/rustc_ast/src/mut_visit.rs
compiler/rustc_ast/src/ptr.rs
compiler/rustc_ast/src/tokenstream.rs
compiler/rustc_ast/src/util/classify.rs
compiler/rustc_ast/src/util/comments.rs
compiler/rustc_ast/src/util/literal.rs
compiler/rustc_ast/src/util/parser.rs
compiler/rustc_ast/src/util/unicode.rs
compiler/rustc_ast/src/visit.rs
compiler/rustc_ast_lowering/src/asm.rs
compiler/rustc_ast_lowering/src/expr.rs
compiler/rustc_ast_lowering/src/item.rs
compiler/rustc_ast_lowering/src/lib.rs
compiler/rustc_ast_lowering/src/path.rs
compiler/rustc_ast_pretty/src/pprust/state.rs
compiler/rustc_ast_pretty/src/pprust/state/expr.rs
compiler/rustc_ast_pretty/src/pprust/state/item.rs
compiler/rustc_attr/src/builtin.rs
compiler/rustc_borrowck/src/borrow_set.rs
compiler/rustc_borrowck/src/dataflow.rs
compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs
compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs
compiler/rustc_borrowck/src/diagnostics/mod.rs
compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
compiler/rustc_borrowck/src/diagnostics/region_errors.rs
compiler/rustc_borrowck/src/diagnostics/region_name.rs
compiler/rustc_borrowck/src/invalidation.rs
compiler/rustc_borrowck/src/lib.rs
compiler/rustc_borrowck/src/nll.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/src/alloc_error_handler.rs
compiler/rustc_builtin_macros/src/assert/context.rs
compiler/rustc_builtin_macros/src/concat.rs
compiler/rustc_builtin_macros/src/concat_bytes.rs
compiler/rustc_builtin_macros/src/deriving/clone.rs
compiler/rustc_builtin_macros/src/deriving/decodable.rs
compiler/rustc_builtin_macros/src/deriving/default.rs
compiler/rustc_builtin_macros/src/deriving/encodable.rs
compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
compiler/rustc_builtin_macros/src/deriving/generic/ty.rs
compiler/rustc_builtin_macros/src/deriving/mod.rs
compiler/rustc_builtin_macros/src/env.rs
compiler/rustc_builtin_macros/src/format.rs
compiler/rustc_builtin_macros/src/format_foreign.rs
compiler/rustc_builtin_macros/src/global_allocator.rs
compiler/rustc_builtin_macros/src/lib.rs
compiler/rustc_builtin_macros/src/test.rs
compiler/rustc_builtin_macros/src/test_harness.rs
compiler/rustc_builtin_macros/src/type_ascribe.rs [new file with mode: 0644]
compiler/rustc_codegen_cranelift/Cargo.lock
compiler/rustc_codegen_cranelift/Cargo.toml
compiler/rustc_codegen_cranelift/src/archive.rs
compiler/rustc_codegen_cranelift/src/base.rs
compiler/rustc_codegen_gcc/Cargo.lock
compiler/rustc_codegen_gcc/Cargo.toml
compiler/rustc_codegen_gcc/src/archive.rs
compiler/rustc_codegen_gcc/src/consts.rs
compiler/rustc_codegen_gcc/src/errors.rs
compiler/rustc_codegen_gcc/src/type_.rs
compiler/rustc_codegen_llvm/Cargo.toml
compiler/rustc_codegen_llvm/src/allocator.rs
compiler/rustc_codegen_llvm/src/attributes.rs
compiler/rustc_codegen_llvm/src/back/archive.rs
compiler/rustc_codegen_llvm/src/back/lto.rs
compiler/rustc_codegen_llvm/src/builder.rs
compiler/rustc_codegen_llvm/src/consts.rs
compiler/rustc_codegen_llvm/src/context.rs
compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/cpp_like.rs
compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/native.rs
compiler/rustc_codegen_llvm/src/declare.rs
compiler/rustc_codegen_llvm/src/errors.rs
compiler/rustc_codegen_llvm/src/llvm/ffi.rs
compiler/rustc_codegen_llvm/src/llvm_util.rs
compiler/rustc_codegen_llvm/src/type_.rs
compiler/rustc_codegen_ssa/Cargo.toml
compiler/rustc_codegen_ssa/src/back/archive.rs
compiler/rustc_codegen_ssa/src/back/link.rs
compiler/rustc_codegen_ssa/src/base.rs
compiler/rustc_codegen_ssa/src/errors.rs
compiler/rustc_codegen_ssa/src/mir/block.rs
compiler/rustc_codegen_ssa/src/mir/debuginfo.rs
compiler/rustc_codegen_ssa/src/mir/place.rs
compiler/rustc_codegen_ssa/src/traits/type_.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/interpret/cast.rs
compiler/rustc_const_eval/src/interpret/eval_context.rs
compiler/rustc_const_eval/src/interpret/intrinsics.rs
compiler/rustc_const_eval/src/interpret/intrinsics/caller_location.rs
compiler/rustc_const_eval/src/interpret/machine.rs
compiler/rustc_const_eval/src/interpret/operator.rs
compiler/rustc_const_eval/src/interpret/step.rs
compiler/rustc_const_eval/src/interpret/terminator.rs
compiler/rustc_const_eval/src/interpret/util.rs
compiler/rustc_const_eval/src/interpret/validity.rs
compiler/rustc_const_eval/src/transform/promote_consts.rs
compiler/rustc_const_eval/src/transform/validate.rs
compiler/rustc_const_eval/src/util/aggregate.rs
compiler/rustc_data_structures/src/fingerprint.rs
compiler/rustc_data_structures/src/graph/scc/mod.rs
compiler/rustc_data_structures/src/graph/vec_graph/mod.rs
compiler/rustc_data_structures/src/intern.rs
compiler/rustc_data_structures/src/memmap.rs
compiler/rustc_data_structures/src/owning_ref/mod.rs
compiler/rustc_data_structures/src/owning_ref/tests.rs
compiler/rustc_data_structures/src/profiling.rs
compiler/rustc_data_structures/src/sorted_map.rs
compiler/rustc_data_structures/src/sorted_map/index_map.rs
compiler/rustc_data_structures/src/sso/either_iter.rs
compiler/rustc_data_structures/src/sso/map.rs
compiler/rustc_data_structures/src/sso/set.rs
compiler/rustc_data_structures/src/stable_hasher.rs
compiler/rustc_data_structures/src/sync.rs
compiler/rustc_data_structures/src/tagged_ptr/drop.rs
compiler/rustc_data_structures/src/vec_map.rs
compiler/rustc_driver/src/lib.rs
compiler/rustc_error_codes/src/error_codes.rs
compiler/rustc_error_codes/src/error_codes/E0492.md
compiler/rustc_error_codes/src/error_codes/E0791.md [new file with mode: 0644]
compiler/rustc_error_messages/locales/en-US/codegen_gcc.ftl
compiler/rustc_error_messages/locales/en-US/codegen_llvm.ftl
compiler/rustc_error_messages/locales/en-US/codegen_ssa.ftl
compiler/rustc_error_messages/locales/en-US/expand.ftl
compiler/rustc_error_messages/locales/en-US/hir_analysis.ftl
compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs
compiler/rustc_errors/src/diagnostic.rs
compiler/rustc_errors/src/diagnostic_impls.rs
compiler/rustc_errors/src/emitter.rs
compiler/rustc_errors/src/json.rs
compiler/rustc_errors/src/lib.rs
compiler/rustc_errors/src/translation.rs
compiler/rustc_expand/src/base.rs
compiler/rustc_expand/src/build.rs
compiler/rustc_expand/src/config.rs
compiler/rustc_expand/src/errors.rs
compiler/rustc_expand/src/expand.rs
compiler/rustc_expand/src/lib.rs
compiler/rustc_expand/src/module.rs
compiler/rustc_expand/src/tests.rs
compiler/rustc_feature/src/builtin_attrs.rs
compiler/rustc_fs_util/src/lib.rs
compiler/rustc_graphviz/src/lib.rs
compiler/rustc_hir/src/arena.rs
compiler/rustc_hir/src/hir.rs
compiler/rustc_hir/src/hir_id.rs
compiler/rustc_hir/src/intravisit.rs
compiler/rustc_hir/src/lang_items.rs
compiler/rustc_hir/src/pat_util.rs
compiler/rustc_hir/src/tests.rs
compiler/rustc_hir_analysis/src/astconv/generics.rs
compiler/rustc_hir_analysis/src/astconv/mod.rs
compiler/rustc_hir_analysis/src/check/check.rs
compiler/rustc_hir_analysis/src/check/compare_method.rs
compiler/rustc_hir_analysis/src/check/region.rs
compiler/rustc_hir_analysis/src/check/wfcheck.rs
compiler/rustc_hir_analysis/src/check_unused.rs
compiler/rustc_hir_analysis/src/collect.rs
compiler/rustc_hir_analysis/src/collect/generics_of.rs
compiler/rustc_hir_analysis/src/collect/lifetimes.rs
compiler/rustc_hir_analysis/src/errors.rs
compiler/rustc_hir_analysis/src/variance/mod.rs
compiler/rustc_hir_pretty/src/lib.rs
compiler/rustc_hir_typeck/src/callee.rs
compiler/rustc_hir_typeck/src/check.rs
compiler/rustc_hir_typeck/src/closure.rs
compiler/rustc_hir_typeck/src/demand.rs
compiler/rustc_hir_typeck/src/expr.rs
compiler/rustc_hir_typeck/src/expr_use_visitor.rs
compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs
compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
compiler/rustc_hir_typeck/src/inherited.rs
compiler/rustc_hir_typeck/src/lib.rs
compiler/rustc_hir_typeck/src/method/confirm.rs
compiler/rustc_hir_typeck/src/method/mod.rs
compiler/rustc_hir_typeck/src/method/probe.rs
compiler/rustc_hir_typeck/src/method/suggest.rs
compiler/rustc_incremental/src/persist/dirty_clean.rs
compiler/rustc_incremental/src/persist/fs.rs
compiler/rustc_index/src/vec.rs
compiler/rustc_infer/src/infer/at.rs
compiler/rustc_infer/src/infer/error_reporting/mod.rs
compiler/rustc_infer/src/infer/error_reporting/note.rs
compiler/rustc_infer/src/infer/error_reporting/note_region.rs [new file with mode: 0644]
compiler/rustc_infer/src/infer/error_reporting/suggest.rs [new file with mode: 0644]
compiler/rustc_infer/src/infer/mod.rs
compiler/rustc_infer/src/infer/note.rs [new file with mode: 0644]
compiler/rustc_interface/src/passes.rs
compiler/rustc_interface/src/queries.rs
compiler/rustc_interface/src/tests.rs
compiler/rustc_lexer/Cargo.toml
compiler/rustc_lexer/src/lib.rs
compiler/rustc_lint/src/builtin.rs
compiler/rustc_lint/src/early.rs
compiler/rustc_lint/src/hidden_unicode_codepoints.rs
compiler/rustc_lint/src/internal.rs
compiler/rustc_lint/src/late.rs
compiler/rustc_lint/src/lib.rs
compiler/rustc_lint/src/pass_by_value.rs
compiler/rustc_lint/src/passes.rs
compiler/rustc_lint/src/types.rs
compiler/rustc_lint/src/unused.rs
compiler/rustc_llvm/build.rs
compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
compiler/rustc_llvm/llvm-wrapper/SymbolWrapper.cpp [new file with mode: 0644]
compiler/rustc_macros/src/diagnostics/diagnostic.rs
compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs
compiler/rustc_macros/src/diagnostics/subdiagnostic.rs
compiler/rustc_macros/src/diagnostics/utils.rs
compiler/rustc_macros/src/query.rs
compiler/rustc_metadata/src/creader.rs
compiler/rustc_metadata/src/fs.rs
compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
compiler/rustc_metadata/src/rmeta/encoder.rs
compiler/rustc_metadata/src/rmeta/table.rs
compiler/rustc_middle/src/arena.rs
compiler/rustc_middle/src/hir/map/mod.rs
compiler/rustc_middle/src/hir/mod.rs
compiler/rustc_middle/src/middle/codegen_fn_attrs.rs
compiler/rustc_middle/src/mir/coverage.rs
compiler/rustc_middle/src/mir/interpret/allocation.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/mir/terminator.rs
compiler/rustc_middle/src/mir/visit.rs
compiler/rustc_middle/src/query/mod.rs
compiler/rustc_middle/src/traits/query.rs
compiler/rustc_middle/src/ty/consts/int.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/generics.rs
compiler/rustc_middle/src/ty/mod.rs
compiler/rustc_middle/src/ty/print/pretty.rs
compiler/rustc_middle/src/ty/query.rs
compiler/rustc_middle/src/ty/sty.rs
compiler/rustc_middle/src/ty/subst.rs
compiler/rustc_middle/src/ty/util.rs
compiler/rustc_middle/src/ty/vtable.rs
compiler/rustc_middle/src/values.rs
compiler/rustc_mir_build/src/build/custom/mod.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/test.rs
compiler/rustc_mir_build/src/build/matches/util.rs
compiler/rustc_mir_build/src/build/mod.rs
compiler/rustc_mir_build/src/build/scope.rs
compiler/rustc_mir_build/src/thir/cx/expr.rs
compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs
compiler/rustc_mir_build/src/thir/pattern/mod.rs
compiler/rustc_mir_dataflow/src/elaborate_drops.rs
compiler/rustc_mir_dataflow/src/framework/direction.rs
compiler/rustc_mir_dataflow/src/framework/engine.rs
compiler/rustc_mir_dataflow/src/framework/lattice.rs
compiler/rustc_mir_dataflow/src/value_analysis.rs
compiler/rustc_mir_transform/src/add_retag.rs
compiler/rustc_mir_transform/src/const_goto.rs
compiler/rustc_mir_transform/src/coverage/debug.rs
compiler/rustc_mir_transform/src/coverage/tests.rs
compiler/rustc_mir_transform/src/dest_prop.rs
compiler/rustc_mir_transform/src/dump_mir.rs
compiler/rustc_mir_transform/src/early_otherwise_branch.rs
compiler/rustc_mir_transform/src/generator.rs
compiler/rustc_mir_transform/src/inline.rs
compiler/rustc_mir_transform/src/match_branches.rs
compiler/rustc_mir_transform/src/pass_manager.rs
compiler/rustc_mir_transform/src/remove_zsts.rs
compiler/rustc_mir_transform/src/shim.rs
compiler/rustc_mir_transform/src/simplify.rs
compiler/rustc_mir_transform/src/simplify_branches.rs
compiler/rustc_mir_transform/src/simplify_comparison_integral.rs
compiler/rustc_mir_transform/src/unreachable_prop.rs
compiler/rustc_monomorphize/src/polymorphize.rs
compiler/rustc_parse/src/parser/attr.rs
compiler/rustc_parse/src/parser/attr_wrapper.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/stmt.rs
compiler/rustc_parse_format/Cargo.toml
compiler/rustc_parse_format/src/lib.rs
compiler/rustc_parse_format/src/tests.rs
compiler/rustc_passes/src/dead.rs
compiler/rustc_passes/src/hir_stats.rs
compiler/rustc_passes/src/liveness.rs
compiler/rustc_passes/src/stability.rs
compiler/rustc_passes/src/upvars.rs
compiler/rustc_privacy/src/lib.rs
compiler/rustc_query_system/src/dep_graph/graph.rs
compiler/rustc_query_system/src/dep_graph/serialized.rs
compiler/rustc_query_system/src/ich/hcx.rs
compiler/rustc_query_system/src/query/caches.rs
compiler/rustc_query_system/src/query/job.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/effective_visibilities.rs
compiler/rustc_resolve/src/imports.rs
compiler/rustc_resolve/src/late.rs
compiler/rustc_resolve/src/late/diagnostics.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/src/opaque.rs
compiler/rustc_session/Cargo.toml
compiler/rustc_session/src/cgu_reuse_tracker.rs
compiler/rustc_session/src/code_stats.rs
compiler/rustc_session/src/config.rs
compiler/rustc_session/src/cstore.rs
compiler/rustc_session/src/errors.rs
compiler/rustc_session/src/filesearch.rs
compiler/rustc_session/src/options.rs
compiler/rustc_session/src/output.rs
compiler/rustc_session/src/session.rs
compiler/rustc_span/src/analyze_source_file.rs
compiler/rustc_span/src/caching_source_map_view.rs
compiler/rustc_span/src/def_id.rs
compiler/rustc_span/src/hygiene.rs
compiler/rustc_span/src/lib.rs
compiler/rustc_span/src/source_map.rs
compiler/rustc_span/src/span_encoding.rs
compiler/rustc_span/src/symbol.rs
compiler/rustc_symbol_mangling/Cargo.toml
compiler/rustc_symbol_mangling/src/typeid.rs
compiler/rustc_target/src/abi/call/sparc64.rs
compiler/rustc_target/src/lib.rs
compiler/rustc_target/src/spec/aarch64_apple_darwin.rs
compiler/rustc_target/src/spec/aarch64_unknown_none.rs
compiler/rustc_target/src/spec/apple/tests.rs
compiler/rustc_target/src/spec/apple_base.rs
compiler/rustc_target/src/spec/i686_apple_darwin.rs
compiler/rustc_target/src/spec/mod.rs
compiler/rustc_target/src/spec/wasm32_unknown_unknown.rs
compiler/rustc_target/src/spec/wasm32_wasi.rs
compiler/rustc_target/src/spec/x86_64_apple_darwin.rs
compiler/rustc_target/src/spec/x86_64_unknown_none.rs
compiler/rustc_trait_selection/src/traits/codegen.rs [deleted file]
compiler/rustc_trait_selection/src/traits/coherence.rs
compiler/rustc_trait_selection/src/traits/const_evaluatable.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/mod.rs
compiler/rustc_trait_selection/src/traits/project.rs
compiler/rustc_trait_selection/src/traits/query/normalize.rs
compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
compiler/rustc_trait_selection/src/traits/select/confirmation.rs
compiler/rustc_trait_selection/src/traits/select/mod.rs
compiler/rustc_trait_selection/src/traits/structural_match.rs
compiler/rustc_trait_selection/src/traits/util.rs
compiler/rustc_trait_selection/src/traits/vtable.rs [new file with mode: 0644]
compiler/rustc_trait_selection/src/traits/wf.rs
compiler/rustc_traits/src/codegen.rs [new file with mode: 0644]
compiler/rustc_traits/src/lib.rs
compiler/rustc_ty_utils/src/abi.rs
compiler/rustc_ty_utils/src/layout.rs
compiler/rustc_ty_utils/src/lib.rs
compiler/rustc_ty_utils/src/structural_match.rs [new file with mode: 0644]
compiler/rustc_type_ir/src/lib.rs
compiler/rustc_type_ir/src/sty.rs
compiler/rustc_type_ir/src/ty_info.rs [new file with mode: 0644]
config.toml.example
library/alloc/src/collections/vec_deque/into_iter.rs
library/alloc/src/collections/vec_deque/mod.rs
library/alloc/src/collections/vec_deque/spec_from_iter.rs [new file with mode: 0644]
library/alloc/src/vec/into_iter.rs
library/alloc/src/vec/mod.rs
library/alloc/tests/vec_deque.rs
library/core/src/clone.rs
library/core/src/cmp.rs
library/core/src/convert/mod.rs
library/core/src/convert/num.rs
library/core/src/future/mod.rs
library/core/src/hint.rs
library/core/src/iter/sources/repeat_n.rs
library/core/src/iter/traits/accum.rs
library/core/src/macros/mod.rs
library/core/src/num/mod.rs
library/core/src/num/nonzero.rs
library/core/src/ops/mod.rs
library/core/src/panicking.rs
library/core/src/prelude/v1.rs
library/core/src/ptr/const_ptr.rs
library/core/src/ptr/mod.rs
library/core/src/ptr/mut_ptr.rs
library/core/src/ptr/non_null.rs
library/core/src/slice/index.rs
library/core/src/slice/mod.rs
library/core/src/str/mod.rs
library/core/src/str/pattern.rs
library/core/src/task/wake.rs
library/std/Cargo.toml
library/std/src/env.rs
library/std/src/fs.rs
library/std/src/fs/tests.rs
library/std/src/panicking.rs
library/std/src/prelude/v1.rs
library/std/src/sync/mpmc/array.rs
library/std/src/sync/mpsc/mod.rs
library/std/src/sys/itron/condvar.rs
library/std/src/sys/itron/mutex.rs
library/std/src/sys/itron/thread.rs
library/std/src/sys/sgx/mod.rs
library/std/src/sys/sgx/thread.rs
library/std/src/sys/sgx/thread_parker.rs [new file with mode: 0644]
library/std/src/sys/solid/io.rs
library/std/src/sys/solid/os.rs
library/std/src/sys/unix/fs.rs
library/std/src/sys/unix/locks/pthread_condvar.rs
library/std/src/sys/unix/thread.rs
library/std/src/sys/unix/thread_parker/pthread.rs
library/std/src/sys/unix/time.rs
library/std/src/sys/unix/weak.rs
library/std/src/sys/windows/process.rs
library/std/src/sys_common/thread_parker/mod.rs
library/std/src/thread/scoped.rs
library/test/src/cli.rs
library/test/src/console.rs
library/test/src/lib.rs
library/test/src/tests.rs
src/bootstrap/Cargo.lock
src/bootstrap/Cargo.toml
src/bootstrap/builder.rs
src/bootstrap/config.rs
src/bootstrap/config/tests.rs [new file with mode: 0644]
src/bootstrap/defaults/config.user.toml
src/bootstrap/flags.rs
src/bootstrap/lib.rs
src/bootstrap/run.rs
src/bootstrap/sanity.rs
src/bootstrap/setup.rs
src/bootstrap/tool.rs
src/ci/docker/host-aarch64/aarch64-gnu/Dockerfile
src/ci/docker/host-x86_64/dist-i686-linux/Dockerfile
src/ci/docker/host-x86_64/dist-powerpc64le-linux/Dockerfile
src/ci/docker/host-x86_64/dist-various-2/build-wasi-toolchain.sh
src/ci/docker/host-x86_64/dist-x86_64-freebsd/Dockerfile
src/ci/docker/host-x86_64/dist-x86_64-illumos/Dockerfile
src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile
src/ci/docker/host-x86_64/dist-x86_64-musl/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/mingw-check/Dockerfile
src/ci/docker/host-x86_64/test-various/Dockerfile
src/ci/docker/host-x86_64/wasm32/Dockerfile
src/ci/docker/host-x86_64/x86_64-gnu-aux/Dockerfile
src/ci/docker/host-x86_64/x86_64-gnu-debug/Dockerfile
src/ci/docker/host-x86_64/x86_64-gnu-distcheck/Dockerfile
src/ci/docker/host-x86_64/x86_64-gnu-llvm-13-stage1/Dockerfile
src/ci/docker/host-x86_64/x86_64-gnu-llvm-13/Dockerfile
src/ci/docker/host-x86_64/x86_64-gnu-nopt/Dockerfile
src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile
src/ci/docker/host-x86_64/x86_64-gnu/Dockerfile
src/ci/docker/scripts/freebsd-toolchain.sh
src/ci/github-actions/ci.yml
src/doc/book
src/doc/embedded-book
src/doc/nomicon
src/doc/reference
src/doc/rust-by-example
src/doc/rustc-dev-guide
src/doc/rustc/src/command-line-arguments.md
src/doc/unstable-book/src/compiler-flags/sanitizer.md
src/doc/unstable-book/src/language-features/abi-efiapi.md
src/librustdoc/Cargo.toml
src/librustdoc/clean/mod.rs
src/librustdoc/clean/types.rs
src/librustdoc/config.rs
src/librustdoc/core.rs
src/librustdoc/html/highlight.rs
src/librustdoc/html/markdown.rs
src/librustdoc/html/markdown/tests.rs
src/librustdoc/html/render/mod.rs
src/librustdoc/html/render/span_map.rs
src/librustdoc/html/sources.rs
src/librustdoc/html/static/css/rustdoc.css
src/librustdoc/html/static/css/themes/ayu.css
src/librustdoc/html/static/css/themes/dark.css
src/librustdoc/html/static/css/themes/light.css
src/librustdoc/html/static/js/main.js
src/librustdoc/html/static/js/scrape-examples.js
src/librustdoc/html/static/scrape-examples-help.md
src/librustdoc/html/static_files.rs
src/librustdoc/json/mod.rs
src/librustdoc/lib.rs
src/librustdoc/passes/bare_urls.rs [deleted file]
src/librustdoc/passes/check_code_block_syntax.rs [deleted file]
src/librustdoc/passes/collect_trait_impls.rs
src/librustdoc/passes/html_tags.rs [deleted file]
src/librustdoc/passes/lint.rs [new file with mode: 0644]
src/librustdoc/passes/lint/bare_urls.rs [new file with mode: 0644]
src/librustdoc/passes/lint/check_code_block_syntax.rs [new file with mode: 0644]
src/librustdoc/passes/lint/html_tags.rs [new file with mode: 0644]
src/librustdoc/passes/mod.rs
src/librustdoc/scrape_examples.rs
src/librustdoc/visit_ast.rs
src/llvm-project
src/test/assembly/asm/aarch64-el2vmsa.rs [new file with mode: 0644]
src/test/assembly/sparc-struct-abi.rs
src/test/codegen/catch-unwind.rs
src/test/codegen/enum-match.rs
src/test/codegen/issue-105386-ub-in-debuginfo.rs [new file with mode: 0644]
src/test/codegen/naked-nocoverage.rs [new file with mode: 0644]
src/test/codegen/pgo-counter-bias.rs [new file with mode: 0644]
src/test/codegen/remap_path_prefix/main.rs
src/test/codegen/repr-transparent-aggregates-1.rs
src/test/codegen/repr-transparent.rs
src/test/codegen/sanitizer-kcfi-add-kcfi-flag.rs [new file with mode: 0644]
src/test/codegen/sanitizer-kcfi-emit-kcfi-operand-bundle-itanium-cxx-abi.rs [new file with mode: 0644]
src/test/codegen/uninit-consts.rs
src/test/mir-opt/76803_regression.encode.SimplifyBranchSame.diff
src/test/mir-opt/bool_compare.opt1.InstCombine.diff
src/test/mir-opt/bool_compare.opt2.InstCombine.diff
src/test/mir-opt/bool_compare.opt3.InstCombine.diff
src/test/mir-opt/bool_compare.opt4.InstCombine.diff
src/test/mir-opt/building/issue_101867.main.built.after.mir
src/test/mir-opt/building/issue_49232.main.built.after.mir
src/test/mir-opt/building/match_false_edges.full_tested_match.built.after.mir
src/test/mir-opt/building/match_false_edges.full_tested_match2.built.after.mir
src/test/mir-opt/building/match_false_edges.main.built.after.mir
src/test/mir-opt/building/simple_match.match_bool.built.after.mir
src/test/mir-opt/const_goto.issue_77355_opt.ConstGoto.diff
src/test/mir-opt/const_goto_const_eval_fail.f.ConstGoto.diff
src/test/mir-opt/const_goto_storage.match_nested_if.ConstGoto.diff
src/test/mir-opt/const_prop/control_flow_simplification.hello.ConstProp.diff
src/test/mir-opt/const_prop/discriminant.main.ConstProp.32bit.diff
src/test/mir-opt/const_prop/discriminant.main.ConstProp.64bit.diff
src/test/mir-opt/const_prop/switch_int.main.ConstProp.diff
src/test/mir-opt/const_prop/switch_int.main.SimplifyConstCondition-after-const-prop.diff
src/test/mir-opt/coverage_graphviz.main.InstrumentCoverage.0.dot
src/test/mir-opt/dataflow-const-prop/enum.main.DataflowConstProp.diff
src/test/mir-opt/dataflow-const-prop/if.main.DataflowConstProp.diff
src/test/mir-opt/dataflow-const-prop/issue_81605.f.DataflowConstProp.diff
src/test/mir-opt/dead-store-elimination/cycle.cycle.DeadStoreElimination.diff
src/test/mir-opt/deaggregator_test_enum_2.test1.Deaggregator.diff
src/test/mir-opt/deduplicate_blocks.is_line_doc_comment_2.DeduplicateBlocks.diff
src/test/mir-opt/deref-patterns/string.foo.PreCodegen.after.mir
src/test/mir-opt/derefer_complex_case.main.Derefer.diff
src/test/mir-opt/derefer_terminator_test.main.Derefer.diff
src/test/mir-opt/dest-prop/branch.foo.DestinationPropagation.diff
src/test/mir-opt/early_otherwise_branch.opt1.EarlyOtherwiseBranch.diff
src/test/mir-opt/early_otherwise_branch.opt2.EarlyOtherwiseBranch.diff
src/test/mir-opt/early_otherwise_branch.opt3.EarlyOtherwiseBranch.diff
src/test/mir-opt/early_otherwise_branch_3_element_tuple.opt1.EarlyOtherwiseBranch.diff
src/test/mir-opt/early_otherwise_branch_68867.try_sum.EarlyOtherwiseBranch.diff
src/test/mir-opt/early_otherwise_branch_noopt.noopt1.EarlyOtherwiseBranch.diff
src/test/mir-opt/early_otherwise_branch_soundness.no_deref_ptr.EarlyOtherwiseBranch.diff
src/test/mir-opt/early_otherwise_branch_soundness.no_downcast.EarlyOtherwiseBranch.diff
src/test/mir-opt/equal_true.opt.InstCombine.diff
src/test/mir-opt/exponential_or.match_tuple.SimplifyCfg-initial.after.mir
src/test/mir-opt/funky_arms.float_to_exponential_common.ConstProp.diff
src/test/mir-opt/generator_drop_cleanup.main-{closure#0}.generator_drop.0.mir
src/test/mir-opt/generator_tiny.main-{closure#0}.generator_resume.0.mir
src/test/mir-opt/if_condition_int.dont_opt_bool.SimplifyComparisonIntegral.diff
src/test/mir-opt/if_condition_int.dont_opt_floats.SimplifyComparisonIntegral.diff
src/test/mir-opt/if_condition_int.dont_remove_comparison.SimplifyComparisonIntegral.diff
src/test/mir-opt/if_condition_int.opt_char.SimplifyComparisonIntegral.diff
src/test/mir-opt/if_condition_int.opt_i8.SimplifyComparisonIntegral.diff
src/test/mir-opt/if_condition_int.opt_multiple_ifs.SimplifyComparisonIntegral.diff
src/test/mir-opt/if_condition_int.opt_negative.SimplifyComparisonIntegral.diff
src/test/mir-opt/if_condition_int.opt_u32.SimplifyComparisonIntegral.diff
src/test/mir-opt/inline/cycle.g.Inline.diff
src/test/mir-opt/inline/cycle.main.Inline.diff
src/test/mir-opt/inline/exponential_runtime.main.Inline.diff [new file with mode: 0644]
src/test/mir-opt/inline/exponential_runtime.rs [new file with mode: 0644]
src/test/mir-opt/inline/inline_cycle.one.Inline.diff
src/test/mir-opt/inline/inline_cycle.two.Inline.diff
src/test/mir-opt/inline/inline_cycle_generic.main.Inline.diff
src/test/mir-opt/inline/inline_diverging.g.Inline.diff
src/test/mir-opt/inline/inline_diverging.h.Inline.diff
src/test/mir-opt/inline/inline_generator.main.Inline.diff
src/test/mir-opt/inline/inline_retag.bar.Inline.after.mir
src/test/mir-opt/inline/inline_shims.drop.Inline.diff
src/test/mir-opt/instrument_coverage.main.InstrumentCoverage.diff
src/test/mir-opt/issue_38669.main.SimplifyCfg-initial.after.mir
src/test/mir-opt/issue_41110.main.ElaborateDrops.after.mir
src/test/mir-opt/issue_41110.test.ElaborateDrops.after.mir
src/test/mir-opt/issue_41888.main.ElaborateDrops.after.mir
src/test/mir-opt/issue_62289.test.ElaborateDrops.before.mir
src/test/mir-opt/issue_73223.main.SimplifyArmIdentity.diff
src/test/mir-opt/issue_99325.main.built.after.mir
src/test/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.mir
src/test/mir-opt/issues/issue_75439.foo.MatchBranchSimplification.diff
src/test/mir-opt/loop_test.main.SimplifyCfg-promote-consts.after.mir
src/test/mir-opt/lower_array_len.array_bound.NormalizeArrayLen.diff
src/test/mir-opt/lower_array_len.array_bound_mut.NormalizeArrayLen.diff
src/test/mir-opt/lower_array_len_e2e.array_bound.PreCodegen.after.mir
src/test/mir-opt/lower_array_len_e2e.array_bound_mut.PreCodegen.after.mir
src/test/mir-opt/lower_slice_len.bound.LowerSliceLenCalls.diff
src/test/mir-opt/match_arm_scopes.complicated_match.SimplifyCfg-initial.after-ElaborateDrops.after.diff
src/test/mir-opt/match_test.main.SimplifyCfg-initial.after.mir
src/test/mir-opt/matches_reduce_branches.bar.MatchBranchSimplification.diff
src/test/mir-opt/matches_reduce_branches.foo.MatchBranchSimplification.diff
src/test/mir-opt/matches_reduce_branches.match_nested_if.MatchBranchSimplification.diff
src/test/mir-opt/matches_u8.exhaustive_match.MatchBranchSimplification.diff
src/test/mir-opt/matches_u8.exhaustive_match_i8.MatchBranchSimplification.diff
src/test/mir-opt/nll/region_subtyping_basic.main.nll.0.32bit.mir
src/test/mir-opt/nll/region_subtyping_basic.main.nll.0.64bit.mir
src/test/mir-opt/no_drop_for_inactive_variant.unwrap.SimplifyCfg-elaborate-drops.after.mir
src/test/mir-opt/not_equal_false.opt.InstCombine.diff
src/test/mir-opt/remove_fake_borrows.match_guard.CleanupNonCodegenStatements.diff
src/test/mir-opt/remove_storage_markers.main.RemoveStorageMarkers.diff
src/test/mir-opt/remove_zsts.get_union.PreCodegen.after.mir [new file with mode: 0644]
src/test/mir-opt/remove_zsts.get_union.RemoveZsts.diff [new file with mode: 0644]
src/test/mir-opt/remove_zsts.rs [new file with mode: 0644]
src/test/mir-opt/remove_zsts_dont_touch_unions.get_union.RemoveZsts.after.mir [deleted file]
src/test/mir-opt/remove_zsts_dont_touch_unions.rs [deleted file]
src/test/mir-opt/retag.array_casts.SimplifyCfg-elaborate-drops.after.mir
src/test/mir-opt/retag.core.ptr-drop_in_place.Test.SimplifyCfg-make_shim.after.mir
src/test/mir-opt/retag.main-{closure#0}.SimplifyCfg-elaborate-drops.after.mir
src/test/mir-opt/retag.main.SimplifyCfg-elaborate-drops.after.mir
src/test/mir-opt/retag.{impl#0}-foo.SimplifyCfg-elaborate-drops.after.mir
src/test/mir-opt/separate_const_switch.identity.SeparateConstSwitch.diff
src/test/mir-opt/separate_const_switch.too_complex.SeparateConstSwitch.diff
src/test/mir-opt/simplify_cfg.main.SimplifyCfg-early-opt.diff
src/test/mir-opt/simplify_cfg.main.SimplifyCfg-initial.diff
src/test/mir-opt/simplify_if.main.SimplifyConstCondition-after-const-prop.diff
src/test/mir-opt/simplify_locals_fixedpoint.foo.SimplifyLocals.diff
src/test/mir-opt/simplify_locals_removes_unused_discriminant_reads.map.SimplifyLocals.diff
src/test/mir-opt/simplify_match.main.ConstProp.diff
src/test/mir-opt/slice_drop_shim.core.ptr-drop_in_place.[String].AddMovesForPackedDrops.before.mir
src/test/mir-opt/sroa.enums.ScalarReplacementOfAggregates.diff
src/test/mir-opt/try_identity_e2e.new.PreCodegen.after.mir
src/test/mir-opt/try_identity_e2e.old.PreCodegen.after.mir
src/test/mir-opt/uninhabited_enum_branching.main.SimplifyCfg-after-uninhabited-enum-branching.after.mir
src/test/mir-opt/uninhabited_enum_branching.main.UninhabitedEnumBranching.diff
src/test/mir-opt/uninhabited_enum_branching2.main.SimplifyCfg-after-uninhabited-enum-branching.after.mir
src/test/mir-opt/uninhabited_enum_branching2.main.UninhabitedEnumBranching.diff
src/test/mir-opt/uninhabited_fallthrough_elimination.eliminate_fallthrough.UninhabitedEnumBranching.diff
src/test/mir-opt/uninhabited_fallthrough_elimination.keep_fallthrough.UninhabitedEnumBranching.diff
src/test/mir-opt/unreachable.main.UnreachablePropagation.diff
src/test/mir-opt/unreachable_diverging.main.UnreachablePropagation.diff
src/test/mir-opt/while_let_loops.change_loop_body.ConstProp.diff
src/test/mir-opt/while_storage.while_loop.PreCodegen.after.mir
src/test/run-make-fulldeps/hotplug_codegen_backend/the_backend.rs
src/test/run-make/coverage-reports/Makefile
src/test/run-make/issue-71519/Makefile
src/test/run-make/macos-deployment-target/Makefile [new file with mode: 0644]
src/test/run-make/macos-deployment-target/with_deployment_target.rs [new file with mode: 0644]
src/test/rustdoc-gui/basic.goml [deleted file]
src/test/rustdoc-gui/docblock-table.goml
src/test/rustdoc-gui/enum-variants.goml
src/test/rustdoc-gui/method-margins.goml
src/test/rustdoc-gui/scrape-examples-button-focus.goml
src/test/rustdoc-gui/scrape-examples-fonts.goml [new file with mode: 0644]
src/test/rustdoc-gui/scrape-examples-toggle.goml [new file with mode: 0644]
src/test/rustdoc-gui/src/scrape_examples/examples/check-many-1.rs [new file with mode: 0644]
src/test/rustdoc-gui/src/scrape_examples/examples/check-many-2.rs [new file with mode: 0644]
src/test/rustdoc-gui/src/scrape_examples/examples/check-many-3.rs [new file with mode: 0644]
src/test/rustdoc-gui/src/scrape_examples/examples/check-many-4.rs [new file with mode: 0644]
src/test/rustdoc-gui/src/scrape_examples/examples/check-many-5.rs [new file with mode: 0644]
src/test/rustdoc-gui/src/scrape_examples/examples/check-many-6.rs [new file with mode: 0644]
src/test/rustdoc-gui/src/scrape_examples/examples/check-many-7.rs [new file with mode: 0644]
src/test/rustdoc-gui/src/scrape_examples/examples/check.rs
src/test/rustdoc-gui/src/scrape_examples/src/lib.rs
src/test/rustdoc-gui/src/test_docs/lib.rs
src/test/rustdoc-gui/stab-badge.goml [new file with mode: 0644]
src/test/rustdoc-gui/toggle-docs.goml
src/test/rustdoc-json/intra-doc-links/auxiliary/enum_variant_in_trait_method.rs [new file with mode: 0644]
src/test/rustdoc-json/intra-doc-links/foreign_variant.rs [new file with mode: 0644]
src/test/rustdoc-json/reexport/auxiliary/trait_with_docs.rs [new file with mode: 0644]
src/test/rustdoc-json/reexport/synthesize_trait_with_docs.rs [new file with mode: 0644]
src/test/rustdoc-json/traits/uses_extern_trait.rs
src/test/rustdoc-ui/const-evalutation-ice.rs [new file with mode: 0644]
src/test/rustdoc-ui/const-evalutation-ice.stderr [new file with mode: 0644]
src/test/rustdoc-ui/doc-cfg.stderr
src/test/rustdoc-ui/issue-91713.stdout
src/test/rustdoc-ui/unable-fulfill-trait.rs [new file with mode: 0644]
src/test/rustdoc-ui/unable-fulfill-trait.stderr [new file with mode: 0644]
src/test/rustdoc-ui/z-help.stdout
src/test/rustdoc/bounds-in-multiple-parts.rs [new file with mode: 0644]
src/test/rustdoc/const-evalutation-ice.rs [deleted file]
src/test/rustdoc/impl-parts.rs
src/test/rustdoc/rfc-2632-const-trait-impl.rs
src/test/rustdoc/whitespace-after-where-clause.enum.html
src/test/rustdoc/whitespace-after-where-clause.struct.html
src/test/rustdoc/whitespace-after-where-clause.union.html
src/test/ui-fulldeps/lint-plugin-cmdline-load.stderr
src/test/ui-fulldeps/lint-plugin-deny-attr.stderr
src/test/ui-fulldeps/lint-plugin-deny-cmdline.stderr
src/test/ui-fulldeps/lint-plugin-forbid-attrs.rs
src/test/ui-fulldeps/lint-plugin-forbid-attrs.stderr
src/test/ui-fulldeps/lint-plugin-forbid-cmdline.rs
src/test/ui-fulldeps/lint-plugin-forbid-cmdline.stderr
src/test/ui-fulldeps/lint-plugin.stderr
src/test/ui-fulldeps/lint-tool-cmdline-allow.stderr
src/test/ui-fulldeps/lint-tool-test.rs
src/test/ui-fulldeps/lint-tool-test.stderr
src/test/ui-fulldeps/pprust-expr-roundtrip.rs
src/test/ui/associated-consts/issue-47814.rs [new file with mode: 0644]
src/test/ui/associated-consts/issue-47814.stderr [new file with mode: 0644]
src/test/ui/associated-consts/issue-93835.rs
src/test/ui/associated-consts/issue-93835.stderr
src/test/ui/associated-inherent-types/issue-104260.rs [new file with mode: 0644]
src/test/ui/associated-inherent-types/normalize-projection-0.rs [new file with mode: 0644]
src/test/ui/associated-inherent-types/normalize-projection-1.rs [new file with mode: 0644]
src/test/ui/associated-inherent-types/struct-generics.rs [new file with mode: 0644]
src/test/ui/async-await/async-await-let-else.drop-tracking.stderr
src/test/ui/async-await/drop-track-bad-field-in-fru.rs [new file with mode: 0644]
src/test/ui/async-await/drop-track-bad-field-in-fru.stderr [new file with mode: 0644]
src/test/ui/async-await/generator-not-future.rs [new file with mode: 0644]
src/test/ui/async-await/generator-not-future.stderr [new file with mode: 0644]
src/test/ui/async-await/in-trait/async-generics-and-bounds.stderr
src/test/ui/async-await/in-trait/async-generics.stderr
src/test/ui/async-await/in-trait/async-lifetimes-and-bounds.rs
src/test/ui/async-await/in-trait/async-lifetimes-and-bounds.stderr [deleted file]
src/test/ui/async-await/in-trait/async-lifetimes.rs
src/test/ui/async-await/in-trait/async-lifetimes.stderr [deleted file]
src/test/ui/async-await/in-trait/implied-bounds.rs [new file with mode: 0644]
src/test/ui/async-await/in-trait/lifetime-mismatch.rs [new file with mode: 0644]
src/test/ui/async-await/in-trait/lifetime-mismatch.stderr [new file with mode: 0644]
src/test/ui/async-await/in-trait/nested-rpit.rs [new file with mode: 0644]
src/test/ui/async-await/in-trait/return-type-suggestion.rs [new file with mode: 0644]
src/test/ui/async-await/in-trait/return-type-suggestion.stderr [new file with mode: 0644]
src/test/ui/async-await/issue-68112.drop_tracking.stderr
src/test/ui/async-await/issue-68112.no_drop_tracking.stderr
src/test/ui/async-await/issue-69446-fnmut-capture.stderr
src/test/ui/async-await/issue-70935-complex-spans.drop_tracking.stderr
src/test/ui/async-await/partial-drop-partial-reinit.drop_tracking.stderr
src/test/ui/async-await/partial-drop-partial-reinit.no_drop_tracking.stderr
src/test/ui/async-await/track-caller/issue-105134.rs [new file with mode: 0644]
src/test/ui/async-await/track-caller/panic-track-caller.rs
src/test/ui/attributes/unused-item-in-attr.rs [new file with mode: 0644]
src/test/ui/attributes/unused-item-in-attr.stderr [new file with mode: 0644]
src/test/ui/auto-traits/bad-generics-on-dyn.rs [new file with mode: 0644]
src/test/ui/auto-traits/bad-generics-on-dyn.stderr [new file with mode: 0644]
src/test/ui/binop/binop-mul-i32-f32.stderr
src/test/ui/borrowck/issue-81899.stderr
src/test/ui/borrowck/issue-88434-minimal-example.stderr
src/test/ui/borrowck/issue-88434-removal-index-should-be-less.stderr
src/test/ui/closures/closure-return-type-must-be-sized.stderr
src/test/ui/closures/issue-90871.rs
src/test/ui/closures/issue-90871.stderr
src/test/ui/coercion/coerce-expect-unsized-ascribed.rs
src/test/ui/coercion/coerce-expect-unsized-ascribed.stderr
src/test/ui/conditional-compilation/cfg-attr-syntax-validation.stderr
src/test/ui/const-generics/defaults/rp_impl_trait_fail.stderr
src/test/ui/const-generics/defaults/self-referential.rs [new file with mode: 0644]
src/test/ui/const-generics/defaults/self-referential.stderr [new file with mode: 0644]
src/test/ui/const-generics/generic_const_exprs/abstract-const-as-cast-3.stderr
src/test/ui/const-generics/generic_const_exprs/const_kind_expr/wf_obligation.rs [new file with mode: 0644]
src/test/ui/const-generics/generic_const_exprs/const_kind_expr/wf_obligation.stderr [new file with mode: 0644]
src/test/ui/const-generics/generic_const_exprs/issue-105257.rs [new file with mode: 0644]
src/test/ui/const-generics/generic_const_exprs/issue-105257.stderr [new file with mode: 0644]
src/test/ui/const-generics/generic_const_exprs/issue-79518-default_trait_method_normalization.stderr
src/test/ui/const-generics/generic_const_exprs/issue-80742.stderr
src/test/ui/const-generics/generic_const_exprs/normed_to_param_is_evaluatable.rs [new file with mode: 0644]
src/test/ui/const-generics/issues/issue-100313.stderr
src/test/ui/const-ptr/forbidden_slices.32bit.stderr
src/test/ui/const-ptr/forbidden_slices.64bit.stderr
src/test/ui/const-ptr/out_of_bounds_read.stderr
src/test/ui/consts/const-eval/const-eval-overflow-3b.stderr
src/test/ui/consts/const-eval/const-eval-overflow-4b.stderr
src/test/ui/consts/const-eval/const_fn_ptr_fail2.stderr
src/test/ui/consts/const-eval/const_panic_track_caller.stderr
src/test/ui/consts/const-eval/heap/alloc_intrinsic_errors.stderr
src/test/ui/consts/const-eval/unwind-abort.stderr
src/test/ui/consts/const-eval/validate_uninhabited_zsts.32bit.stderr
src/test/ui/consts/const-eval/validate_uninhabited_zsts.64bit.stderr
src/test/ui/consts/const-float-bits-reject-conv.stderr
src/test/ui/consts/const-mut-refs/mut_ref_in_final_dynamic_check.stderr
src/test/ui/consts/const_in_pattern/accept_structural.rs
src/test/ui/consts/const_in_pattern/reject_non_structural.rs
src/test/ui/consts/const_unsafe_unreachable_ub.stderr
src/test/ui/consts/extra-const-ub/detect-extra-ub.with_flag.stderr
src/test/ui/consts/issue-miri-1910.stderr
src/test/ui/consts/miri_unleashed/abi-mismatch.stderr
src/test/ui/consts/miri_unleashed/assoc_const.stderr
src/test/ui/consts/miri_unleashed/drop.stderr
src/test/ui/consts/miri_unleashed/tls.stderr
src/test/ui/consts/missing_span_in_backtrace.rs [new file with mode: 0644]
src/test/ui/consts/missing_span_in_backtrace.stderr [new file with mode: 0644]
src/test/ui/consts/offset_from_ub.stderr
src/test/ui/consts/offset_ub.stderr
src/test/ui/consts/ptr_comparisons.stderr
src/test/ui/consts/recursive.stderr
src/test/ui/consts/uninhabited-const-issue-61744.stderr
src/test/ui/debuginfo/issue-105386-debuginfo-ub.rs [new file with mode: 0644]
src/test/ui/diagnostic-width/long-E0308.rs [new file with mode: 0644]
src/test/ui/diagnostic-width/long-E0308.stderr [new file with mode: 0644]
src/test/ui/did_you_mean/issue-39802-show-5-trait-impls.stderr
src/test/ui/disambiguate-identical-names.stderr
src/test/ui/drop/drop_order.rs
src/test/ui/drop/issue-103107.rs [new file with mode: 0644]
src/test/ui/duplicate/duplicate-type-parameter.stderr
src/test/ui/dyn-star/no-implicit-dyn-star.stderr
src/test/ui/enum-discriminant/issue-104519.rs [new file with mode: 0644]
src/test/ui/enum/issue-67945-2.rs
src/test/ui/enum/issue-67945-2.stderr
src/test/ui/error-codes/E0275.stderr
src/test/ui/feature-gates/feature-gate-impl_trait_in_fn_trait_return.stderr
src/test/ui/feature-gates/feature-gate-linkage.rs
src/test/ui/feature-gates/feature-gate-linkage.stderr
src/test/ui/fn/signature-error-reporting-under-verbose.rs [new file with mode: 0644]
src/test/ui/fn/signature-error-reporting-under-verbose.stderr [new file with mode: 0644]
src/test/ui/generator/print/generator-print-verbose-1.stderr
src/test/ui/generic-associated-types/cross-crate-bounds.stderr
src/test/ui/generic-associated-types/own-bound-span.rs [new file with mode: 0644]
src/test/ui/generic-associated-types/own-bound-span.stderr [new file with mode: 0644]
src/test/ui/generic-associated-types/self-outlives-lint.stderr
src/test/ui/half-open-range-patterns/exclusive_range_pattern_syntax_collision.stderr
src/test/ui/half-open-range-patterns/exclusive_range_pattern_syntax_collision2.stderr
src/test/ui/half-open-range-patterns/exclusive_range_pattern_syntax_collision3.stderr
src/test/ui/impl-trait/equality.stderr
src/test/ui/impl-trait/in-trait/where-clause.rs [new file with mode: 0644]
src/test/ui/impl-trait/nested-return-type4.rs [new file with mode: 0644]
src/test/ui/impl-trait/nested-return-type4.stderr [new file with mode: 0644]
src/test/ui/impl-trait/recursive-type-alias-impl-trait-declaration-too-subtle.stderr
src/test/ui/inference/deref-suggestion.stderr
src/test/ui/infinite/infinite-recursion-const-fn.stderr
src/test/ui/inline-const/expr-with-block-err.rs [new file with mode: 0644]
src/test/ui/inline-const/expr-with-block-err.stderr [new file with mode: 0644]
src/test/ui/inline-const/expr-with-block.rs [new file with mode: 0644]
src/test/ui/invalid/invalid-no-sanitize.stderr
src/test/ui/issues/issue-105330.rs [new file with mode: 0644]
src/test/ui/issues/issue-105330.stderr [new file with mode: 0644]
src/test/ui/issues/issue-20413.stderr
src/test/ui/issues/issue-23122-2.stderr
src/test/ui/issues/issue-23966.stderr
src/test/ui/issues/issue-24352.stderr
src/test/ui/issues/issue-31173.stderr
src/test/ui/issues/issue-33941.stderr
src/test/ui/issues/issue-34334.stderr
src/test/ui/issues/issue-35976.rs
src/test/ui/issues/issue-35976.stderr [deleted file]
src/test/ui/issues/issue-35976.unimported.stderr [new file with mode: 0644]
src/test/ui/issues/issue-47486.stderr
src/test/ui/issues/issue-66923-show-error-for-correct-call.stderr
src/test/ui/iterators/collect-into-array.stderr
src/test/ui/iterators/collect-into-slice.stderr
src/test/ui/kindck/kindck-copy.stderr
src/test/ui/lazy-type-alias-impl-trait/branches.stderr
src/test/ui/lazy-type-alias-impl-trait/recursion4.stderr
src/test/ui/let-else/let-else-deref-coercion.stderr
src/test/ui/lexer/lex-bad-char-literals-6.stderr
src/test/ui/limits/issue-55878.stderr
src/test/ui/linkage-attr/auxiliary/def_external.rs [new file with mode: 0644]
src/test/ui/linkage-attr/auxiliary/def_illtyped_external.rs [deleted file]
src/test/ui/linkage-attr/linkage-import.rs [new file with mode: 0644]
src/test/ui/linkage-attr/linkage-requires-raw-ptr.rs [deleted file]
src/test/ui/linkage-attr/linkage-requires-raw-ptr.stderr [deleted file]
src/test/ui/linkage-attr/linkage2.rs
src/test/ui/linkage-attr/linkage2.stderr
src/test/ui/lint/issue-104897.rs [new file with mode: 0644]
src/test/ui/lint/issue-104897.stderr [new file with mode: 0644]
src/test/ui/lint/issue-97094.interleaved.stderr [deleted file]
src/test/ui/lint/issue-97094.nointerleaved.stderr [deleted file]
src/test/ui/lint/issue-97094.rs
src/test/ui/lint/issue-97094.stderr [new file with mode: 0644]
src/test/ui/lint/lint-missing-copy-implementations-allow.rs [new file with mode: 0644]
src/test/ui/lint/unused/issue-54538-unused-parens-lint.fixed
src/test/ui/lint/unused/issue-54538-unused-parens-lint.rs
src/test/ui/lint/unused/issue-54538-unused-parens-lint.stderr
src/test/ui/lint/unused/issue-88519-unused-paren.rs
src/test/ui/macros/issue-103529.rs [new file with mode: 0644]
src/test/ui/macros/issue-103529.stderr [new file with mode: 0644]
src/test/ui/macros/macro-in-expression-context.stderr
src/test/ui/macros/syntax-error-recovery.stderr
src/test/ui/maximal_mir_to_hir_coverage.rs [new file with mode: 0644]
src/test/ui/methods/issues/issue-90315.stderr
src/test/ui/mir/issue-95978-validator-lifetime-comparison.rs [deleted file]
src/test/ui/mir/mir_ascription_coercion.rs
src/test/ui/mir/validate/issue-95978-validator-lifetime-comparison.rs [new file with mode: 0644]
src/test/ui/mir/validate/needs-reveal-all.rs [new file with mode: 0644]
src/test/ui/mismatched_types/binops.stderr
src/test/ui/mismatched_types/closure-arg-count.stderr
src/test/ui/mismatched_types/closure-arg-type-mismatch.stderr
src/test/ui/mismatched_types/issue-36053-2.stderr
src/test/ui/mismatched_types/wrap-suggestion-privacy.stderr
src/test/ui/never_type/issue-13352.stderr
src/test/ui/nll/user-annotations/issue-57731-ascibed-coupled-types.rs
src/test/ui/nll/user-annotations/issue-57731-ascibed-coupled-types.stderr
src/test/ui/nll/user-annotations/type_ascription_static_lifetime.rs
src/test/ui/nll/user-annotations/type_ascription_static_lifetime.stderr
src/test/ui/numbers-arithmetic/not-suggest-float-literal.stderr
src/test/ui/numbers-arithmetic/suggest-float-literal.stderr
src/test/ui/numeric/numeric-cast-binop.stderr
src/test/ui/numeric/numeric-cast-no-fix.stderr
src/test/ui/object-safety/object-safety-supertrait-mentions-GAT.stderr
src/test/ui/on-unimplemented/sum.rs [new file with mode: 0644]
src/test/ui/on-unimplemented/sum.stderr [new file with mode: 0644]
src/test/ui/parser/bare-struct-body.stderr
src/test/ui/parser/chained-comparison-suggestion.stderr
src/test/ui/parser/expr-as-stmt.fixed
src/test/ui/parser/expr-as-stmt.rs
src/test/ui/parser/expr-as-stmt.stderr
src/test/ui/parser/issue-101477-enum.stderr
src/test/ui/parser/issue-103869.rs [new file with mode: 0644]
src/test/ui/parser/issue-103869.stderr [new file with mode: 0644]
src/test/ui/parser/macro/issue-37113.stderr
src/test/ui/pptypedef.stderr
src/test/ui/print_type_sizes/async.rs [new file with mode: 0644]
src/test/ui/print_type_sizes/async.stdout [new file with mode: 0644]
src/test/ui/print_type_sizes/generator.rs [new file with mode: 0644]
src/test/ui/print_type_sizes/generator.stdout [new file with mode: 0644]
src/test/ui/privacy/effective_visibilities.rs
src/test/ui/privacy/effective_visibilities.stderr
src/test/ui/proc-macro/attr-invalid-exprs.stderr
src/test/ui/proc-macro/attribute.rs
src/test/ui/proc-macro/attribute.stderr
src/test/ui/proc-macro/expand-expr.stderr
src/test/ui/query-system/fn-sig-cycle-arity.rs [new file with mode: 0644]
src/test/ui/query-system/fn-sig-cycle-arity.stderr [new file with mode: 0644]
src/test/ui/range/issue-54505-no-literals.stderr
src/test/ui/range/issue-54505.stderr
src/test/ui/range/issue-73553-misinterp-range-literal.stderr
src/test/ui/raw-ref-op/raw-ref-temp-deref.rs
src/test/ui/raw-ref-op/raw-ref-temp.rs
src/test/ui/raw-ref-op/raw-ref-temp.stderr
src/test/ui/reachable/expr_type.rs
src/test/ui/reachable/expr_type.stderr
src/test/ui/recursion/issue-83150.stderr
src/test/ui/regions/closure-in-projection-issue-97405.rs
src/test/ui/regions/closure-in-projection-issue-97405.stderr
src/test/ui/regions/issue-102374.rs
src/test/ui/regions/issue-102374.stderr
src/test/ui/resolve/bad-module.stderr
src/test/ui/resolve/issue-101749-2.rs [new file with mode: 0644]
src/test/ui/resolve/issue-101749-2.stderr [new file with mode: 0644]
src/test/ui/resolve/issue-101749.fixed [new file with mode: 0644]
src/test/ui/resolve/issue-101749.rs [new file with mode: 0644]
src/test/ui/resolve/issue-101749.stderr [new file with mode: 0644]
src/test/ui/resolve/issue-105069.rs [new file with mode: 0644]
src/test/ui/resolve/issue-105069.stderr [new file with mode: 0644]
src/test/ui/resolve/issue-24968.stderr
src/test/ui/resolve/typo-suggestion-mistyped-in-path.stderr
src/test/ui/resolve/use_suggestion.stderr
src/test/ui/return/tail-expr-as-potential-return.rs
src/test/ui/return/tail-expr-as-potential-return.stderr
src/test/ui/rfc-1445-restrict-constants-in-patterns/match-requires-both-partialeq-and-eq.rs
src/test/ui/rfc-2497-if-let-chains/disallowed-positions.stderr
src/test/ui/rfc-2632-const-trait-impl/issue-79450.rs [new file with mode: 0644]
src/test/ui/rfc-2632-const-trait-impl/issue-79450.stderr [new file with mode: 0644]
src/test/ui/span/issue-71363.rs
src/test/ui/span/issue-71363.stderr
src/test/ui/span/multiline-span-simple.stderr
src/test/ui/stats/hir-stats.stderr
src/test/ui/structs/struct-fn-in-definition.rs
src/test/ui/structs/struct-fn-in-definition.stderr
src/test/ui/structs/struct-record-suggestion.stderr
src/test/ui/structs/unresolved-struct-with-fru.rs [new file with mode: 0644]
src/test/ui/structs/unresolved-struct-with-fru.stderr [new file with mode: 0644]
src/test/ui/suggestions/assoc-const-as-fn.rs [new file with mode: 0644]
src/test/ui/suggestions/assoc-const-as-fn.stderr [new file with mode: 0644]
src/test/ui/suggestions/bound-suggestions.stderr
src/test/ui/suggestions/crate-or-module-typo.stderr
src/test/ui/suggestions/dont-suggest-try_into-in-macros.stderr
src/test/ui/suggestions/dont-suggest-ufcs-for-const.stderr
src/test/ui/suggestions/issue-105226.rs [new file with mode: 0644]
src/test/ui/suggestions/issue-105226.stderr [new file with mode: 0644]
src/test/ui/suggestions/option-to-bool.stderr
src/test/ui/suggestions/try-removing-the-field.rs
src/test/ui/suggestions/try-removing-the-field.stderr
src/test/ui/suggestions/unnecessary_dot_for_floating_point_literal.stderr
src/test/ui/trait-bounds/impl-bound-with-references-error.rs [new file with mode: 0644]
src/test/ui/trait-bounds/impl-bound-with-references-error.stderr [new file with mode: 0644]
src/test/ui/trait-bounds/impl-missing-where-clause-lifetimes-from-trait.rs [new file with mode: 0644]
src/test/ui/trait-bounds/impl-missing-where-clause-lifetimes-from-trait.stderr [new file with mode: 0644]
src/test/ui/traits/default-method/rustc_must_implement_one_of_duplicates.rs
src/test/ui/traits/default-method/rustc_must_implement_one_of_duplicates.stderr
src/test/ui/traits/default-method/rustc_must_implement_one_of_misuse.rs
src/test/ui/traits/default-method/rustc_must_implement_one_of_misuse.stderr
src/test/ui/traits/issue-79458.stderr
src/test/ui/traits/issue-91949-hangs-on-recursion.stderr
src/test/ui/traits/object/issue-44454-1.rs [new file with mode: 0644]
src/test/ui/traits/object/issue-44454-1.stderr [new file with mode: 0644]
src/test/ui/traits/object/issue-44454-2.rs [new file with mode: 0644]
src/test/ui/traits/object/issue-44454-2.stderr [new file with mode: 0644]
src/test/ui/traits/object/issue-44454-3.rs [new file with mode: 0644]
src/test/ui/traits/object/issue-44454-3.stderr [new file with mode: 0644]
src/test/ui/traits/suggest-where-clause.stderr
src/test/ui/try-trait/bad-interconversion.stderr
src/test/ui/type-alias-impl-trait/self-referential-2.stderr
src/test/ui/type-alias-impl-trait/self-referential-4.stderr
src/test/ui/type-alias-impl-trait/self-referential.stderr
src/test/ui/type/type-ascription-precedence.stderr
src/test/ui/type/type-ascription-soundness.rs
src/test/ui/type/type-ascription-soundness.stderr
src/test/ui/type/type-ascription.rs
src/test/ui/type/type-check-defaults.stderr
src/test/ui/type/type-check/assignment-in-if.stderr
src/test/ui/type/type-params-in-different-spaces-1.stderr
src/test/ui/typeck/issue-104582.rs [new file with mode: 0644]
src/test/ui/typeck/issue-104582.stderr [new file with mode: 0644]
src/test/ui/typeck/issue-13853.stderr
src/test/ui/typeck/issue-81293.stderr
src/test/ui/typeck/issue-91267.rs
src/test/ui/typeck/issue-91267.stderr
src/test/ui/typeck/path-to-method-sugg-unresolved-expr.rs [new file with mode: 0644]
src/test/ui/typeck/path-to-method-sugg-unresolved-expr.stderr [new file with mode: 0644]
src/test/ui/ufcs/ufcs-qpath-self-mismatch.stderr
src/test/ui/wf/hir-wf-canonicalized.rs [new file with mode: 0644]
src/test/ui/wf/hir-wf-canonicalized.stderr [new file with mode: 0644]
src/test/ui/wrong-mul-method-signature.stderr
src/tools/cargo
src/tools/clippy/CHANGELOG.md
src/tools/clippy/README.md
src/tools/clippy/book/src/SUMMARY.md
src/tools/clippy/book/src/configuration.md
src/tools/clippy/book/src/development/adding_lints.md
src/tools/clippy/book/src/development/proposals/syntax-tree-patterns.md [new file with mode: 0644]
src/tools/clippy/clippy_dev/src/new_lint.rs
src/tools/clippy/clippy_lints/src/almost_complete_letter_range.rs
src/tools/clippy/clippy_lints/src/approx_const.rs
src/tools/clippy/clippy_lints/src/attrs.rs
src/tools/clippy/clippy_lints/src/casts/cast_abs_to_unsigned.rs
src/tools/clippy/clippy_lints/src/casts/cast_lossless.rs
src/tools/clippy/clippy_lints/src/casts/cast_possible_truncation.rs
src/tools/clippy/clippy_lints/src/casts/cast_slice_different_sizes.rs
src/tools/clippy/clippy_lints/src/casts/cast_slice_from_raw_parts.rs
src/tools/clippy/clippy_lints/src/casts/mod.rs
src/tools/clippy/clippy_lints/src/casts/ptr_as_ptr.rs
src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs
src/tools/clippy/clippy_lints/src/checked_conversions.rs
src/tools/clippy/clippy_lints/src/collapsible_if.rs
src/tools/clippy/clippy_lints/src/declared_lints.rs
src/tools/clippy/clippy_lints/src/dereference.rs
src/tools/clippy/clippy_lints/src/derive.rs
src/tools/clippy/clippy_lints/src/disallowed_types.rs
src/tools/clippy/clippy_lints/src/doc.rs
src/tools/clippy/clippy_lints/src/eta_reduction.rs
src/tools/clippy/clippy_lints/src/exit.rs
src/tools/clippy/clippy_lints/src/format_args.rs
src/tools/clippy/clippy_lints/src/from_over_into.rs
src/tools/clippy/clippy_lints/src/functions/misnamed_getters.rs [new file with mode: 0644]
src/tools/clippy/clippy_lints/src/functions/mod.rs
src/tools/clippy/clippy_lints/src/functions/result.rs
src/tools/clippy/clippy_lints/src/future_not_send.rs
src/tools/clippy/clippy_lints/src/if_then_some_else_none.rs
src/tools/clippy/clippy_lints/src/index_refutable_slice.rs
src/tools/clippy/clippy_lints/src/instant_subtraction.rs
src/tools/clippy/clippy_lints/src/lib.rs
src/tools/clippy/clippy_lints/src/lifetimes.rs
src/tools/clippy/clippy_lints/src/macro_use.rs
src/tools/clippy/clippy_lints/src/manual_bits.rs
src/tools/clippy/clippy_lints/src/manual_clamp.rs
src/tools/clippy/clippy_lints/src/manual_is_ascii_check.rs
src/tools/clippy/clippy_lints/src/manual_let_else.rs
src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs
src/tools/clippy/clippy_lints/src/manual_rem_euclid.rs
src/tools/clippy/clippy_lints/src/manual_retain.rs
src/tools/clippy/clippy_lints/src/manual_strip.rs
src/tools/clippy/clippy_lints/src/matches/mod.rs
src/tools/clippy/clippy_lints/src/matches/try_err.rs
src/tools/clippy/clippy_lints/src/mem_replace.rs
src/tools/clippy/clippy_lints/src/methods/cloned_instead_of_copied.rs
src/tools/clippy/clippy_lints/src/methods/err_expect.rs
src/tools/clippy/clippy_lints/src/methods/filter_map_next.rs
src/tools/clippy/clippy_lints/src/methods/is_digit_ascii_radix.rs
src/tools/clippy/clippy_lints/src/methods/map_clone.rs
src/tools/clippy/clippy_lints/src/methods/map_unwrap_or.rs
src/tools/clippy/clippy_lints/src/methods/mod.rs
src/tools/clippy/clippy_lints/src/methods/option_as_ref_deref.rs
src/tools/clippy/clippy_lints/src/methods/option_map_unwrap_or.rs
src/tools/clippy/clippy_lints/src/methods/str_splitn.rs
src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs
src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs
src/tools/clippy/clippy_lints/src/missing_enforced_import_rename.rs
src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs
src/tools/clippy/clippy_lints/src/no_effect.rs
src/tools/clippy/clippy_lints/src/ptr.rs
src/tools/clippy/clippy_lints/src/ranges.rs
src/tools/clippy/clippy_lints/src/redundant_closure_call.rs
src/tools/clippy/clippy_lints/src/redundant_field_names.rs
src/tools/clippy/clippy_lints/src/redundant_pub_crate.rs
src/tools/clippy/clippy_lints/src/redundant_static_lifetimes.rs
src/tools/clippy/clippy_lints/src/returns.rs
src/tools/clippy/clippy_lints/src/single_component_path_imports.rs
src/tools/clippy/clippy_lints/src/transmute/mod.rs
src/tools/clippy/clippy_lints/src/transmute/transmute_ptr_to_ref.rs
src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs
src/tools/clippy/clippy_lints/src/unnecessary_self_imports.rs
src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs
src/tools/clippy/clippy_lints/src/unsafe_removed_from_name.rs
src/tools/clippy/clippy_lints/src/unused_rounding.rs
src/tools/clippy/clippy_lints/src/use_self.rs
src/tools/clippy/clippy_lints/src/utils/conf.rs
src/tools/clippy/clippy_lints/src/utils/internal_lints/lint_without_lint_pass.rs
src/tools/clippy/clippy_lints/src/utils/internal_lints/metadata_collector.rs
src/tools/clippy/clippy_lints/src/utils/internal_lints/msrv_attr_impl.rs
src/tools/clippy/clippy_lints/src/wildcard_imports.rs
src/tools/clippy/clippy_utils/src/ast_utils.rs
src/tools/clippy/clippy_utils/src/attrs.rs
src/tools/clippy/clippy_utils/src/eager_or_lazy.rs
src/tools/clippy/clippy_utils/src/lib.rs
src/tools/clippy/clippy_utils/src/msrvs.rs
src/tools/clippy/clippy_utils/src/paths.rs
src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs
src/tools/clippy/clippy_utils/src/source.rs
src/tools/clippy/clippy_utils/src/sugg.rs
src/tools/clippy/clippy_utils/src/ty.rs
src/tools/clippy/clippy_utils/src/usage.rs
src/tools/clippy/clippy_utils/src/visitors.rs
src/tools/clippy/lintcheck/src/main.rs
src/tools/clippy/rust-toolchain
src/tools/clippy/src/driver.rs
src/tools/clippy/tests/ui-internal/invalid_msrv_attr_impl.fixed
src/tools/clippy/tests/ui-internal/invalid_msrv_attr_impl.rs
src/tools/clippy/tests/ui-internal/unnecessary_def_path_hardcoded_path.stderr
src/tools/clippy/tests/ui-toml/allow_mixed_uninlined_format_args/clippy.toml [new file with mode: 0644]
src/tools/clippy/tests/ui-toml/allow_mixed_uninlined_format_args/uninlined_format_args.fixed [new file with mode: 0644]
src/tools/clippy/tests/ui-toml/allow_mixed_uninlined_format_args/uninlined_format_args.rs [new file with mode: 0644]
src/tools/clippy/tests/ui-toml/allow_mixed_uninlined_format_args/uninlined_format_args.stderr [new file with mode: 0644]
src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr
src/tools/clippy/tests/ui/almost_complete_letter_range.fixed
src/tools/clippy/tests/ui/almost_complete_letter_range.rs
src/tools/clippy/tests/ui/almost_complete_letter_range.stderr
src/tools/clippy/tests/ui/cast_abs_to_unsigned.fixed
src/tools/clippy/tests/ui/cast_abs_to_unsigned.rs
src/tools/clippy/tests/ui/cast_abs_to_unsigned.stderr
src/tools/clippy/tests/ui/cast_lossless_bool.fixed
src/tools/clippy/tests/ui/cast_lossless_bool.rs
src/tools/clippy/tests/ui/cast_lossless_bool.stderr
src/tools/clippy/tests/ui/cfg_attr_rustfmt.fixed
src/tools/clippy/tests/ui/cfg_attr_rustfmt.rs
src/tools/clippy/tests/ui/cfg_attr_rustfmt.stderr
src/tools/clippy/tests/ui/checked_conversions.fixed
src/tools/clippy/tests/ui/checked_conversions.rs
src/tools/clippy/tests/ui/checked_conversions.stderr
src/tools/clippy/tests/ui/cloned_instead_of_copied.fixed
src/tools/clippy/tests/ui/cloned_instead_of_copied.rs
src/tools/clippy/tests/ui/cloned_instead_of_copied.stderr
src/tools/clippy/tests/ui/doc_unnecessary_unsafe.rs [deleted file]
src/tools/clippy/tests/ui/doc_unnecessary_unsafe.stderr [deleted file]
src/tools/clippy/tests/ui/err_expect.fixed
src/tools/clippy/tests/ui/err_expect.rs
src/tools/clippy/tests/ui/err_expect.stderr
src/tools/clippy/tests/ui/eta.fixed
src/tools/clippy/tests/ui/eta.rs
src/tools/clippy/tests/ui/eta.stderr
src/tools/clippy/tests/ui/explicit_auto_deref.fixed
src/tools/clippy/tests/ui/explicit_auto_deref.rs
src/tools/clippy/tests/ui/filter_map_next_fixable.fixed
src/tools/clippy/tests/ui/filter_map_next_fixable.rs
src/tools/clippy/tests/ui/filter_map_next_fixable.stderr
src/tools/clippy/tests/ui/from_over_into.fixed
src/tools/clippy/tests/ui/from_over_into.rs
src/tools/clippy/tests/ui/from_over_into.stderr
src/tools/clippy/tests/ui/if_then_some_else_none.rs
src/tools/clippy/tests/ui/if_then_some_else_none.stderr
src/tools/clippy/tests/ui/macro_use_imports.stderr
src/tools/clippy/tests/ui/manual_clamp.rs
src/tools/clippy/tests/ui/manual_clamp.stderr
src/tools/clippy/tests/ui/manual_is_ascii_check.fixed
src/tools/clippy/tests/ui/manual_is_ascii_check.rs
src/tools/clippy/tests/ui/manual_is_ascii_check.stderr
src/tools/clippy/tests/ui/manual_let_else.rs
src/tools/clippy/tests/ui/manual_let_else.stderr
src/tools/clippy/tests/ui/manual_rem_euclid.fixed
src/tools/clippy/tests/ui/manual_rem_euclid.rs
src/tools/clippy/tests/ui/manual_rem_euclid.stderr
src/tools/clippy/tests/ui/manual_retain.fixed
src/tools/clippy/tests/ui/manual_retain.rs
src/tools/clippy/tests/ui/manual_retain.stderr
src/tools/clippy/tests/ui/manual_split_once.fixed
src/tools/clippy/tests/ui/manual_split_once.rs
src/tools/clippy/tests/ui/manual_split_once.stderr
src/tools/clippy/tests/ui/manual_str_repeat.fixed
src/tools/clippy/tests/ui/manual_str_repeat.rs
src/tools/clippy/tests/ui/manual_str_repeat.stderr
src/tools/clippy/tests/ui/manual_strip.rs
src/tools/clippy/tests/ui/manual_strip.stderr
src/tools/clippy/tests/ui/map_unwrap_or.rs
src/tools/clippy/tests/ui/map_unwrap_or.stderr
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/match_expr_like_matches_macro.stderr
src/tools/clippy/tests/ui/mem_replace.fixed
src/tools/clippy/tests/ui/mem_replace.rs
src/tools/clippy/tests/ui/mem_replace.stderr
src/tools/clippy/tests/ui/min_rust_version_attr.rs
src/tools/clippy/tests/ui/min_rust_version_attr.stderr
src/tools/clippy/tests/ui/min_rust_version_invalid_attr.stderr
src/tools/clippy/tests/ui/misnamed_getters.rs [new file with mode: 0644]
src/tools/clippy/tests/ui/misnamed_getters.stderr [new file with mode: 0644]
src/tools/clippy/tests/ui/missing_const_for_fn/cant_be_const.rs
src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.rs
src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.stderr
src/tools/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_question_mark.fixed
src/tools/clippy/tests/ui/needless_question_mark.rs
src/tools/clippy/tests/ui/needless_question_mark.stderr
src/tools/clippy/tests/ui/needless_return.fixed
src/tools/clippy/tests/ui/needless_return.rs
src/tools/clippy/tests/ui/needless_return.stderr
src/tools/clippy/tests/ui/needless_splitn.fixed
src/tools/clippy/tests/ui/needless_splitn.rs
src/tools/clippy/tests/ui/needless_splitn.stderr
src/tools/clippy/tests/ui/option_as_ref_deref.fixed
src/tools/clippy/tests/ui/option_as_ref_deref.rs
src/tools/clippy/tests/ui/option_as_ref_deref.stderr
src/tools/clippy/tests/ui/ptr_as_ptr.fixed
src/tools/clippy/tests/ui/ptr_as_ptr.rs
src/tools/clippy/tests/ui/ptr_as_ptr.stderr
src/tools/clippy/tests/ui/range_contains.fixed
src/tools/clippy/tests/ui/range_contains.rs
src/tools/clippy/tests/ui/range_contains.stderr
src/tools/clippy/tests/ui/redundant_closure_call_fixable.fixed
src/tools/clippy/tests/ui/redundant_closure_call_fixable.rs
src/tools/clippy/tests/ui/redundant_closure_call_fixable.stderr
src/tools/clippy/tests/ui/redundant_field_names.fixed
src/tools/clippy/tests/ui/redundant_field_names.rs
src/tools/clippy/tests/ui/redundant_field_names.stderr
src/tools/clippy/tests/ui/redundant_static_lifetimes.fixed
src/tools/clippy/tests/ui/redundant_static_lifetimes.rs
src/tools/clippy/tests/ui/redundant_static_lifetimes.stderr
src/tools/clippy/tests/ui/result_large_err.rs
src/tools/clippy/tests/ui/seek_from_current.fixed
src/tools/clippy/tests/ui/seek_from_current.rs
src/tools/clippy/tests/ui/seek_from_current.stderr
src/tools/clippy/tests/ui/seek_to_start_instead_of_rewind.fixed
src/tools/clippy/tests/ui/seek_to_start_instead_of_rewind.rs
src/tools/clippy/tests/ui/seek_to_start_instead_of_rewind.stderr
src/tools/clippy/tests/ui/transmute_ptr_to_ref.fixed
src/tools/clippy/tests/ui/transmute_ptr_to_ref.rs
src/tools/clippy/tests/ui/transmute_ptr_to_ref.stderr
src/tools/clippy/tests/ui/undocumented_unsafe_blocks.rs
src/tools/clippy/tests/ui/undocumented_unsafe_blocks.stderr
src/tools/clippy/tests/ui/uninlined_format_args.fixed
src/tools/clippy/tests/ui/uninlined_format_args.rs
src/tools/clippy/tests/ui/uninlined_format_args.stderr
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_lazy_eval.fixed
src/tools/clippy/tests/ui/unnecessary_lazy_eval.rs
src/tools/clippy/tests/ui/unnecessary_lazy_eval.stderr
src/tools/clippy/tests/ui/unnecessary_operation.fixed
src/tools/clippy/tests/ui/unnecessary_operation.rs
src/tools/clippy/tests/ui/unnecessary_safety_comment.rs [new file with mode: 0644]
src/tools/clippy/tests/ui/unnecessary_safety_comment.stderr [new file with mode: 0644]
src/tools/clippy/tests/ui/unnecessary_to_owned.fixed
src/tools/clippy/tests/ui/unnecessary_to_owned.rs
src/tools/clippy/tests/ui/unnecessary_to_owned.stderr
src/tools/clippy/tests/ui/unnecessary_unsafety_doc.rs [new file with mode: 0644]
src/tools/clippy/tests/ui/unnecessary_unsafety_doc.stderr [new file with mode: 0644]
src/tools/clippy/tests/ui/unnested_or_patterns.fixed
src/tools/clippy/tests/ui/unnested_or_patterns.rs
src/tools/clippy/tests/ui/unnested_or_patterns.stderr
src/tools/clippy/tests/ui/unused_rounding.fixed
src/tools/clippy/tests/ui/unused_rounding.rs
src/tools/clippy/tests/ui/unused_rounding.stderr
src/tools/clippy/tests/ui/use_self.fixed
src/tools/clippy/tests/ui/use_self.rs
src/tools/clippy/tests/ui/use_self.stderr
src/tools/clippy/triagebot.toml
src/tools/collect-license-metadata/Cargo.toml [new file with mode: 0644]
src/tools/collect-license-metadata/src/licenses.rs [new file with mode: 0644]
src/tools/collect-license-metadata/src/main.rs [new file with mode: 0644]
src/tools/collect-license-metadata/src/path_tree.rs [new file with mode: 0644]
src/tools/collect-license-metadata/src/reuse.rs [new file with mode: 0644]
src/tools/compiletest/src/header.rs
src/tools/compiletest/src/main.rs
src/tools/compiletest/src/runtest.rs
src/tools/compiletest/src/util.rs
src/tools/generate-copyright/Cargo.toml [new file with mode: 0644]
src/tools/generate-copyright/src/main.rs [new file with mode: 0644]
src/tools/jsondoclint/src/validator.rs
src/tools/jsondoclint/src/validator/tests.rs [new file with mode: 0644]
src/tools/miri/CONTRIBUTING.md
src/tools/miri/Cargo.lock
src/tools/miri/Cargo.toml
src/tools/miri/cargo-miri/src/phases.rs
src/tools/miri/cargo-miri/src/setup.rs
src/tools/miri/ci.sh
src/tools/miri/miri
src/tools/miri/rust-version
src/tools/miri/src/bin/miri.rs
src/tools/miri/src/borrow_tracker/mod.rs [new file with mode: 0644]
src/tools/miri/src/borrow_tracker/stacked_borrows/diagnostics.rs [new file with mode: 0644]
src/tools/miri/src/borrow_tracker/stacked_borrows/item.rs [new file with mode: 0644]
src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs [new file with mode: 0644]
src/tools/miri/src/borrow_tracker/stacked_borrows/stack.rs [new file with mode: 0644]
src/tools/miri/src/concurrency/data_race.rs
src/tools/miri/src/concurrency/init_once.rs
src/tools/miri/src/concurrency/sync.rs
src/tools/miri/src/concurrency/thread.rs
src/tools/miri/src/concurrency/vector_clock.rs
src/tools/miri/src/concurrency/weak_memory.rs
src/tools/miri/src/diagnostics.rs
src/tools/miri/src/eval.rs
src/tools/miri/src/helpers.rs
src/tools/miri/src/intptrcast.rs
src/tools/miri/src/lib.rs
src/tools/miri/src/machine.rs
src/tools/miri/src/shims/env.rs
src/tools/miri/src/shims/foreign_items.rs
src/tools/miri/src/shims/panic.rs
src/tools/miri/src/shims/time.rs
src/tools/miri/src/shims/tls.rs
src/tools/miri/src/shims/unix/fs.rs
src/tools/miri/src/shims/unix/linux/sync.rs
src/tools/miri/src/shims/unix/sync.rs
src/tools/miri/src/shims/unix/thread.rs
src/tools/miri/src/shims/windows/sync.rs
src/tools/miri/src/shims/windows/thread.rs
src/tools/miri/src/stacked_borrows/diagnostics.rs [deleted file]
src/tools/miri/src/stacked_borrows/item.rs [deleted file]
src/tools/miri/src/stacked_borrows/mod.rs [deleted file]
src/tools/miri/src/stacked_borrows/stack.rs [deleted file]
src/tools/miri/src/tag_gc.rs
src/tools/miri/tests/fail/abort-terminator.stderr
src/tools/miri/tests/fail/alloc/deallocate-bad-alignment.stderr
src/tools/miri/tests/fail/alloc/deallocate-bad-size.stderr
src/tools/miri/tests/fail/alloc/deallocate-twice.stderr
src/tools/miri/tests/fail/alloc/global_system_mixup.stderr
src/tools/miri/tests/fail/alloc/reallocate-bad-size.stderr
src/tools/miri/tests/fail/alloc/reallocate-dangling.stderr
src/tools/miri/tests/fail/alloc/stack_free.stderr
src/tools/miri/tests/fail/box-cell-alias.stderr
src/tools/miri/tests/fail/concurrency/windows_join_detached.stderr
src/tools/miri/tests/fail/crates/tokio_mvp.stderr
src/tools/miri/tests/fail/dangling_pointers/storage_dead_dangling.stderr
src/tools/miri/tests/fail/data_race/stack_pop_race.stderr
src/tools/miri/tests/fail/function_calls/exported_symbol_abi_mismatch.rs
src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind2.both.stderr
src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind2.definition.stderr
src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind2.rs
src/tools/miri/tests/fail/generator-pinned-moved.stderr
src/tools/miri/tests/fail/intrinsics/simd-float-to-int.stderr
src/tools/miri/tests/fail/intrinsics/simd-gather.stderr
src/tools/miri/tests/fail/intrinsics/simd-scatter.stderr
src/tools/miri/tests/fail/issue-miri-1112.stderr
src/tools/miri/tests/fail/never_transmute_void.stderr
src/tools/miri/tests/fail/panic/bad_unwind.stderr
src/tools/miri/tests/fail/panic/double_panic.stderr
src/tools/miri/tests/fail/panic/no_std.stderr
src/tools/miri/tests/fail/panic/panic_abort1.stderr
src/tools/miri/tests/fail/panic/panic_abort2.stderr
src/tools/miri/tests/fail/panic/panic_abort3.stderr
src/tools/miri/tests/fail/panic/panic_abort4.stderr
src/tools/miri/tests/fail/provenance/provenance_transmute.stderr
src/tools/miri/tests/fail/shims/fs/isolated_file.stderr
src/tools/miri/tests/fail/shims/fs/mkstemp_immutable_arg.stderr
src/tools/miri/tests/fail/shims/fs/unix_open_missing_required_mode.stderr
src/tools/miri/tests/fail/should-pass/cpp20_rwc_syncs.stderr
src/tools/miri/tests/fail/stacked_borrows/aliasing_mut1.stderr
src/tools/miri/tests/fail/stacked_borrows/aliasing_mut2.stderr
src/tools/miri/tests/fail/stacked_borrows/aliasing_mut3.stderr
src/tools/miri/tests/fail/stacked_borrows/aliasing_mut4.stderr
src/tools/miri/tests/fail/stacked_borrows/box_exclusive_violation1.stderr
src/tools/miri/tests/fail/stacked_borrows/box_noalias_violation.stderr
src/tools/miri/tests/fail/stacked_borrows/deallocate_against_protector1.stderr
src/tools/miri/tests/fail/stacked_borrows/deallocate_against_protector2.stderr
src/tools/miri/tests/fail/stacked_borrows/illegal_dealloc1.stderr
src/tools/miri/tests/fail/stacked_borrows/illegal_write6.stderr
src/tools/miri/tests/fail/stacked_borrows/invalidate_against_protector1.stderr
src/tools/miri/tests/fail/stacked_borrows/invalidate_against_protector2.stderr
src/tools/miri/tests/fail/stacked_borrows/invalidate_against_protector3.stderr
src/tools/miri/tests/fail/stacked_borrows/issue-miri-1050-1.stderr
src/tools/miri/tests/fail/stacked_borrows/issue-miri-1050-2.stderr
src/tools/miri/tests/fail/stacked_borrows/mut_exclusive_violation1.stderr
src/tools/miri/tests/fail/stacked_borrows/newtype_pair_retagging.stderr
src/tools/miri/tests/fail/stacked_borrows/newtype_retagging.stderr
src/tools/miri/tests/fail/stacked_borrows/notunpin_dereferenceable_fakeread.rs [deleted file]
src/tools/miri/tests/fail/stacked_borrows/notunpin_dereferenceable_fakeread.stderr [deleted file]
src/tools/miri/tests/fail/stacked_borrows/pointer_smuggling.stderr
src/tools/miri/tests/fail/stacked_borrows/retag_data_race_read.stderr
src/tools/miri/tests/fail/stacked_borrows/retag_data_race_write.stderr
src/tools/miri/tests/fail/stacked_borrows/return_invalid_mut.stderr
src/tools/miri/tests/fail/stacked_borrows/return_invalid_mut_option.stderr
src/tools/miri/tests/fail/stacked_borrows/return_invalid_mut_tuple.stderr
src/tools/miri/tests/fail/stacked_borrows/return_invalid_shr.stderr
src/tools/miri/tests/fail/stacked_borrows/return_invalid_shr_option.stderr
src/tools/miri/tests/fail/stacked_borrows/return_invalid_shr_tuple.stderr
src/tools/miri/tests/fail/stacked_borrows/shr_frozen_violation1.stderr
src/tools/miri/tests/fail/stacked_borrows/zst_slice.stderr
src/tools/miri/tests/fail/uninit_buffer.stderr
src/tools/miri/tests/fail/uninit_buffer_with_provenance.stderr
src/tools/miri/tests/many-seeds/scoped-thread-leak.rs [new file with mode: 0644]
src/tools/miri/tests/pass/box.stderr
src/tools/miri/tests/pass/concurrency/scope.rs [new file with mode: 0644]
src/tools/miri/tests/pass/stacked-borrows/future-self-referential.rs [new file with mode: 0644]
src/tools/rustfmt/src/closures.rs
src/tools/rustfmt/src/imports.rs
src/tools/tidy/src/deps.rs
src/version
triagebot.toml

index ebbed11d04b8d775c98b0c020db6db8f3ee42172..2b6e96b467e3555d0611aa845aabd522b575714c 100644 (file)
@@ -301,7 +301,7 @@ jobs:
           - name: dist-x86_64-apple
             env:
               SCRIPT: "./x.py dist bootstrap --include-default-paths --host=x86_64-apple-darwin --target=x86_64-apple-darwin"
-              RUST_CONFIGURE_ARGS: "--enable-full-tools --enable-sanitizers --enable-profiler --set rust.jemalloc --set llvm.ninja=false"
+              RUST_CONFIGURE_ARGS: "--enable-full-tools --enable-sanitizers --enable-profiler --set rust.jemalloc --set llvm.ninja=false --set rust.lto=thin"
               RUSTC_RETRY_LINKER_ON_SEGFAULT: 1
               MACOSX_DEPLOYMENT_TARGET: 10.7
               SELECT_XCODE: /Applications/Xcode_13.4.1.app
@@ -309,7 +309,7 @@ jobs:
               NO_DEBUG_ASSERTIONS: 1
               NO_OVERFLOW_CHECKS: 1
               DIST_REQUIRE_ALL_TOOLS: 1
-            os: macos-latest
+            os: macos-12-xl
           - name: dist-apple-various
             env:
               SCRIPT: "./x.py dist bootstrap --include-default-paths --host='' --target=aarch64-apple-ios,x86_64-apple-ios,aarch64-apple-ios-sim"
@@ -320,7 +320,7 @@ jobs:
               NO_LLVM_ASSERTIONS: 1
               NO_DEBUG_ASSERTIONS: 1
               NO_OVERFLOW_CHECKS: 1
-            os: macos-latest
+            os: macos-12-xl
           - name: dist-x86_64-apple-alt
             env:
               SCRIPT: "./x.py dist bootstrap --include-default-paths"
@@ -331,7 +331,7 @@ jobs:
               NO_LLVM_ASSERTIONS: 1
               NO_DEBUG_ASSERTIONS: 1
               NO_OVERFLOW_CHECKS: 1
-            os: macos-latest
+            os: macos-12-xl
           - name: x86_64-apple-1
             env:
               SCRIPT: "./x.py --stage 2 test --exclude src/test/ui --exclude src/test/rustdoc --exclude src/test/run-make-fulldeps"
@@ -342,7 +342,7 @@ jobs:
               NO_LLVM_ASSERTIONS: 1
               NO_DEBUG_ASSERTIONS: 1
               NO_OVERFLOW_CHECKS: 1
-            os: macos-latest
+            os: macos-12-xl
           - name: x86_64-apple-2
             env:
               SCRIPT: "./x.py --stage 2 test src/test/ui src/test/rustdoc src/test/run-make-fulldeps"
@@ -353,7 +353,7 @@ jobs:
               NO_LLVM_ASSERTIONS: 1
               NO_DEBUG_ASSERTIONS: 1
               NO_OVERFLOW_CHECKS: 1
-            os: macos-latest
+            os: macos-12-xl
           - name: dist-aarch64-apple
             env:
               SCRIPT: "./x.py dist bootstrap --include-default-paths --stage 2"
@@ -368,7 +368,7 @@ jobs:
               NO_OVERFLOW_CHECKS: 1
               DIST_REQUIRE_ALL_TOOLS: 1
               JEMALLOC_SYS_WITH_LG_PAGE: 14
-            os: macos-latest
+            os: macos-12-xl
           - name: x86_64-msvc-1
             env:
               RUST_CONFIGURE_ARGS: "--build=x86_64-pc-windows-msvc --enable-profiler"
@@ -430,7 +430,7 @@ jobs:
             os: windows-latest-xl
           - name: dist-x86_64-msvc
             env:
-              RUST_CONFIGURE_ARGS: "--build=x86_64-pc-windows-msvc --host=x86_64-pc-windows-msvc --target=x86_64-pc-windows-msvc --enable-full-tools --enable-profiler"
+              RUST_CONFIGURE_ARGS: "--build=x86_64-pc-windows-msvc --host=x86_64-pc-windows-msvc --target=x86_64-pc-windows-msvc --enable-full-tools --enable-profiler --set rust.lto=thin"
               SCRIPT: PGO_HOST=x86_64-pc-windows-msvc src/ci/pgo.sh python x.py dist bootstrap --include-default-paths
               DIST_REQUIRE_ALL_TOOLS: 1
             os: windows-latest-xl
index c85049378061317bd6fe82f2fcc0a574a8318c89..4011a6fa6b95b3e0104a4f99ab5c912790d7a333 100644 (file)
@@ -28,7 +28,7 @@
 [submodule "src/llvm-project"]
        path = src/llvm-project
        url = https://github.com/rust-lang/llvm-project.git
-       branch = rustc/15.0-2022-08-09
+       branch = rustc/15.0-2022-12-07
 [submodule "src/doc/embedded-book"]
        path = src/doc/embedded-book
        url = https://github.com/rust-embedded/book.git
index 7d43dbc9e0640e35e88a129d78b2b46450ea3ffa..5d05a09f038938cf4e26241a3883989ee8e4dc22 100644 (file)
@@ -92,6 +92,15 @@ version = "1.0.65"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "98161a4e3e2184da77bb14f02184cdd111e83bbbcc9979dfee3c44b9a85f5602"
 
+[[package]]
+name = "ar_archive_writer"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "276881980556fdadeb88aa1ffc667e4d2e8fe72531dfabcb7a82bb3c9ea9ba31"
+dependencies = [
+ "object",
+]
+
 [[package]]
 name = "array_tool"
 version = "1.0.3"
@@ -572,6 +581,7 @@ dependencies = [
  "libc",
  "num-integer",
  "num-traits",
+ "serde",
  "time",
  "winapi",
 ]
@@ -721,6 +731,16 @@ dependencies = [
  "rustc-semver",
 ]
 
+[[package]]
+name = "collect-license-metadata"
+version = "0.1.0"
+dependencies = [
+ "anyhow",
+ "serde",
+ "serde_json",
+ "spdx-rs",
+]
+
 [[package]]
 name = "color-eyre"
 version = "0.6.2"
@@ -789,9 +809,9 @@ dependencies = [
 
 [[package]]
 name = "compiler_builtins"
-version = "0.1.84"
+version = "0.1.85"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "989b2c1ca6e90ad06fdc69d1d1862fa28d27a977be6d92ae2fa762cf61fe0b10"
+checksum = "13e81c6cd7ab79f51a0c927d22858d61ad12bd0b3865f0b13ece02a4486aeabb"
 dependencies = [
  "cc",
  "rustc-std-workspace-core",
@@ -906,9 +926,9 @@ version = "0.0.0"
 
 [[package]]
 name = "cpufeatures"
-version = "0.2.1"
+version = "0.2.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "95059428f66df56b63431fdb4e1947ed2190586af5c5a8a8b71122bdf5a7f469"
+checksum = "28d997bd5e24a5928dd43e46dc529867e207907fe0b239c3477d924f7f2ca320"
 dependencies = [
  "libc",
 ]
@@ -1085,12 +1105,6 @@ version = "0.1.13"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8"
 
-[[package]]
-name = "difference"
-version = "2.0.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "524cbf6897b527295dff137cec09ecf3a05f4fddffd7dfcd1585403449e74198"
-
 [[package]]
 name = "digest"
 version = "0.10.2"
@@ -1162,6 +1176,12 @@ dependencies = [
  "syn",
 ]
 
+[[package]]
+name = "dissimilar"
+version = "1.0.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8c97b9233581d84b8e1e689cdd3a47b6f69770084fc246e86a7f78b0d9c1d4a5"
+
 [[package]]
 name = "dlmalloc"
 version = "0.2.3"
@@ -1283,11 +1303,11 @@ dependencies = [
 
 [[package]]
 name = "expect-test"
-version = "1.0.1"
+version = "1.4.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ceb96f3eaa0d4e8769c52dacfd4eb60183b817ed2f176171b3c691d5022b0f2e"
+checksum = "1d4661aca38d826eb7c72fe128e4238220616de4c0cc00db7bfc38e2e1364dd3"
 dependencies = [
- "difference",
+ "dissimilar",
  "once_cell",
 ]
 
@@ -1543,6 +1563,15 @@ dependencies = [
  "termcolor",
 ]
 
+[[package]]
+name = "generate-copyright"
+version = "0.1.0"
+dependencies = [
+ "anyhow",
+ "serde",
+ "serde_json",
+]
+
 [[package]]
 name = "generic-array"
 version = "0.14.4"
@@ -2076,9 +2105,9 @@ checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55"
 
 [[package]]
 name = "libc"
-version = "0.2.135"
+version = "0.2.138"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "68783febc7782c6c5cb401fbda4de5a9898be1762314da0bb2c10ced61f18b0c"
+checksum = "db6d7e329c562c5dfab7a46a2afabc8b987ab9a4834c9d1ca04dc54c1546cef8"
 dependencies = [
  "rustc-std-workspace-core",
 ]
@@ -3495,6 +3524,7 @@ dependencies = [
 name = "rustc_codegen_ssa"
 version = "0.0.0"
 dependencies = [
+ "ar_archive_writer",
  "bitflags",
  "cc",
  "itertools",
@@ -4138,6 +4168,7 @@ dependencies = [
 name = "rustc_parse_format"
 version = "0.0.0"
 dependencies = [
+ "rustc_data_structures",
  "rustc_lexer",
 ]
 
@@ -4312,12 +4343,14 @@ dependencies = [
  "rustc_feature",
  "rustc_fs_util",
  "rustc_hir",
+ "rustc_index",
  "rustc_lint_defs",
  "rustc_macros",
  "rustc_serialize",
  "rustc_span",
  "rustc_target",
  "smallvec",
+ "termize",
  "tracing",
  "winapi",
 ]
@@ -4371,6 +4404,7 @@ dependencies = [
  "rustc_span",
  "rustc_target",
  "tracing",
+ "twox-hash",
 ]
 
 [[package]]
@@ -4593,9 +4627,9 @@ dependencies = [
 
 [[package]]
 name = "rustix"
-version = "0.36.3"
+version = "0.36.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0b1fbb4dfc4eb1d390c02df47760bb19a84bb80b301ecc947ab5406394d8223e"
+checksum = "a3807b5d10909833d3e9acd1eb5fb988f79376ff10fce42937de71a449c4c588"
 dependencies = [
  "bitflags",
  "errno",
@@ -4854,6 +4888,35 @@ dependencies = [
  "winapi",
 ]
 
+[[package]]
+name = "spdx-expression"
+version = "0.5.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "53d7ac03c67c572d85049d6db815e20a4a19b41b3d5cca732ac582342021ad77"
+dependencies = [
+ "nom",
+ "serde",
+ "thiserror",
+ "tracing",
+]
+
+[[package]]
+name = "spdx-rs"
+version = "0.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b3c02f6eb7e7b4100c272f685a9ccaccaab302324e8c7ec3e2ee72340fb29ff3"
+dependencies = [
+ "chrono",
+ "log",
+ "nom",
+ "serde",
+ "spdx-expression",
+ "strum",
+ "strum_macros",
+ "thiserror",
+ "uuid",
+]
+
 [[package]]
 name = "stable_deref_trait"
 version = "1.2.0"
@@ -4957,6 +5020,25 @@ version = "0.10.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
 
+[[package]]
+name = "strum"
+version = "0.24.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "063e6045c0e62079840579a7e47a355ae92f60eb74daaf156fb1e84ba164e63f"
+
+[[package]]
+name = "strum_macros"
+version = "0.24.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1e385be0d24f186b4ce2f9982191e7101bb737312ad61c1f2f984f34bcf85d59"
+dependencies = [
+ "heck",
+ "proc-macro2",
+ "quote",
+ "rustversion",
+ "syn",
+]
+
 [[package]]
 name = "syn"
 version = "1.0.102"
@@ -5313,6 +5395,17 @@ dependencies = [
  "tracing-subscriber",
 ]
 
+[[package]]
+name = "twox-hash"
+version = "1.6.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "97fee6b57c6a41524a810daee9286c02d7752c4253064d0b05472833a438f675"
+dependencies = [
+ "cfg-if 1.0.0",
+ "rand 0.8.5",
+ "static_assertions",
+]
+
 [[package]]
 name = "type-map"
 version = "0.4.0"
@@ -5346,9 +5439,9 @@ checksum = "56dee185309b50d1f11bfedef0fe6d036842e3fb77413abef29f8f8d1c5d4c1c"
 
 [[package]]
 name = "ui_test"
-version = "0.4.0"
+version = "0.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bf4559da3fe6b481f8674a29379677cb9606cd6f75fc254a2c9834c55638503d"
+checksum = "54ddb6f31025943e2f9d59237f433711c461a43d9415974c3eb3a4902edc1c1f"
 dependencies = [
  "bstr 1.0.1",
  "cargo_metadata 0.15.0",
@@ -5586,6 +5679,15 @@ version = "0.1.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "8772a4ccbb4e89959023bc5b7cb8623a795caa7092d99f3aa9501b9484d4557d"
 
+[[package]]
+name = "uuid"
+version = "0.8.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7"
+dependencies = [
+ "getrandom 0.2.0",
+]
+
 [[package]]
 name = "valuable"
 version = "0.1.0"
index 13a98eedde86704608ea81167f78ea3e3f5cae69..000c10a1f906d6c161f1835651754679e35c3bd9 100644 (file)
@@ -39,6 +39,8 @@ members = [
   "src/tools/bump-stage0",
   "src/tools/replace-version-placeholder",
   "src/tools/lld-wrapper",
+  "src/tools/collect-license-metadata",
+  "src/tools/generate-copyright",
 ]
 
 exclude = [
diff --git a/LICENSES/LLVM-exception.txt b/LICENSES/LLVM-exception.txt
new file mode 100644 (file)
index 0000000..fa4b725
--- /dev/null
@@ -0,0 +1,15 @@
+---- LLVM Exceptions to the Apache 2.0 License ----
+
+   As an exception, if, as a result of your compiling your source code, portions
+   of this Software are embedded into an Object form of such source code, you
+   may redistribute such embedded portions in such Object form without complying
+   with the conditions of Sections 4(a), 4(b) and 4(d) of the License.
+
+   In addition, if you combine or link compiled forms of this Software with
+   software that is licensed under the GPLv2 ("Combined Software") and if a
+   court of competent jurisdiction determines that the patent provision (Section
+   3), the indemnity provision (Section 9) or other Section of the License
+   conflicts with the conditions of the GPLv2, you may retroactively and
+   prospectively choose to deem waived or otherwise exclude such Section(s) of
+   the License, but only in their entirety and only with respect to the Combined
+   Software.
index 11e7b80f85efd1a7a49c68c4220105de4589d41e..9c2cf58efed4a30ef37d0f522a1b6d6ba96c6e03 100644 (file)
@@ -354,7 +354,7 @@ fn layout_of_struct_or_enum<'a, V: Idx, F: Deref<Target = &'a LayoutS<V>> + Debu
                 if !always_sized { StructKind::MaybeUnsized } else { StructKind::AlwaysSized }
             };
 
-            let mut st = self.univariant(dl, &variants[v], &repr, kind)?;
+            let mut st = self.univariant(dl, &variants[v], repr, kind)?;
             st.variants = Variants::Single { index: v };
 
             if is_unsafe_cell {
@@ -457,7 +457,7 @@ struct TmpLayout<V: Idx> {
             let mut variant_layouts = variants
                 .iter_enumerated()
                 .map(|(j, v)| {
-                    let mut st = self.univariant(dl, v, &repr, StructKind::AlwaysSized)?;
+                    let mut st = self.univariant(dl, v, repr, StructKind::AlwaysSized)?;
                     st.variants = Variants::Single { index: j };
 
                     align = align.max(st.align);
@@ -647,8 +647,8 @@ struct TmpLayout<V: Idx> {
             .map(|(i, field_layouts)| {
                 let mut st = self.univariant(
                     dl,
-                    &field_layouts,
-                    &repr,
+                    field_layouts,
+                    repr,
                     StructKind::Prefixed(min_ity.size(), prefix_align),
                 )?;
                 st.variants = Variants::Single { index: i };
@@ -755,7 +755,7 @@ struct TmpLayout<V: Idx> {
             // Try to use a ScalarPair for all tagged enums.
             let mut common_prim = None;
             let mut common_prim_initialized_in_all_variants = true;
-            for (field_layouts, layout_variant) in iter::zip(&*variants, &layout_variants) {
+            for (field_layouts, layout_variant) in iter::zip(variants, &layout_variants) {
                 let FieldsShape::Arbitrary { ref offsets, .. } = layout_variant.fields else {
                     panic!();
                 };
index 85693259cd0153eb02fbb6b0b8424a9fe69a7124..4ca59144b29902ebf2377ae220e5c9f8678f9a10 100644 (file)
@@ -1,6 +1,5 @@
 #![cfg_attr(feature = "nightly", feature(step_trait, rustc_attrs, min_specialization))]
 
-use std::convert::{TryFrom, TryInto};
 use std::fmt;
 #[cfg(feature = "nightly")]
 use std::iter::Step;
@@ -9,6 +8,8 @@
 use std::str::FromStr;
 
 use bitflags::bitflags;
+#[cfg(feature = "nightly")]
+use rustc_data_structures::stable_hasher::StableOrd;
 use rustc_index::vec::{Idx, IndexVec};
 #[cfg(feature = "nightly")]
 use rustc_macros::HashStable_Generic;
@@ -403,6 +404,11 @@ pub struct Size {
     raw: u64,
 }
 
+// Safety: Ord is implement as just comparing numerical values and numerical values
+// are not changed by (de-)serialization.
+#[cfg(feature = "nightly")]
+unsafe impl StableOrd for Size {}
+
 // This is debug-printed a lot in larger structs, don't waste too much space there
 impl fmt::Debug for Size {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
index 3db8adb2a244424a52cbf667128b7a722f92150a..2286712f02565974f2623901844c82328e562ff6 100644 (file)
@@ -2,7 +2,6 @@
 use crate::{Float, FloatConvert, ParseError, Round, Status, StatusAnd};
 
 use core::cmp::{self, Ordering};
-use core::convert::TryFrom;
 use core::fmt::{self, Write};
 use core::marker::PhantomData;
 use core::mem;
index 46dbbd83d19054e2c2aaf8e4751c68a9aaf974d0..4fae5ef845f7d95a2cfb947a25daeada6e46cdf7 100644 (file)
@@ -28,7 +28,7 @@
 use std::alloc::Layout;
 use std::cell::{Cell, RefCell};
 use std::cmp;
-use std::marker::{PhantomData, Send};
+use std::marker::PhantomData;
 use std::mem::{self, MaybeUninit};
 use std::ptr::{self, NonNull};
 use std::slice;
index fc70b68e27fd2aa76652223ca3bbef057487dfad..2e86970bcfdc7d1ae84ff14adb70cd2bd9a26311 100644 (file)
@@ -33,7 +33,6 @@
 use rustc_span::source_map::{respan, Spanned};
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
 use rustc_span::{Span, DUMMY_SP};
-use std::convert::TryFrom;
 use std::fmt;
 use std::mem;
 use thin_vec::{thin_vec, ThinVec};
@@ -1179,7 +1178,7 @@ pub fn to_bound(&self) -> Option<GenericBound> {
     pub fn peel_parens(&self) -> &Expr {
         let mut expr = self;
         while let ExprKind::Paren(inner) = &expr.kind {
-            expr = &inner;
+            expr = inner;
         }
         expr
     }
@@ -1312,8 +1311,10 @@ pub struct Closure {
     pub movability: Movability,
     pub fn_decl: P<FnDecl>,
     pub body: P<Expr>,
-    /// The span of the argument block `|...|`.
+    /// The span of the declaration block: 'move |...| -> ...'
     pub fn_decl_span: Span,
+    /// The span of the argument block `|...|`
+    pub fn_arg_span: Span,
 }
 
 /// Limit types of a range (inclusive or exclusive)
@@ -2031,7 +2032,7 @@ impl Ty {
     pub fn peel_refs(&self) -> &Self {
         let mut final_ty = self;
         while let TyKind::Rptr(_, MutTy { ty, .. }) = &final_ty.kind {
-            final_ty = &ty;
+            final_ty = ty;
         }
         final_ty
     }
@@ -2521,10 +2522,7 @@ pub struct Variant {
 #[derive(Clone, Encodable, Decodable, Debug)]
 pub enum UseTreeKind {
     /// `use prefix` or `use prefix as rename`
-    ///
-    /// The extra `NodeId`s are for HIR lowering, when additional statements are created for each
-    /// namespace.
-    Simple(Option<Ident>, NodeId, NodeId),
+    Simple(Option<Ident>),
     /// `use prefix::{...}`
     Nested(Vec<(UseTree, NodeId)>),
     /// `use prefix::*`
@@ -2543,8 +2541,8 @@ pub struct UseTree {
 impl UseTree {
     pub fn ident(&self) -> Ident {
         match self.kind {
-            UseTreeKind::Simple(Some(rename), ..) => rename,
-            UseTreeKind::Simple(None, ..) => {
+            UseTreeKind::Simple(Some(rename)) => rename,
+            UseTreeKind::Simple(None) => {
                 self.prefix.segments.last().expect("empty prefix in a simple import").ident
             }
             _ => panic!("`UseTree::ident` can only be used on a simple import"),
index cb3c54fa03ce56dd4395d543179bdd1842d4fcb7..a45ee6067bbaedb5c541d91dd2ccff91f23228e1 100644 (file)
@@ -410,11 +410,7 @@ pub fn noop_visit_use_tree<T: MutVisitor>(use_tree: &mut UseTree, vis: &mut T) {
     let UseTree { prefix, kind, span } = use_tree;
     vis.visit_path(prefix);
     match kind {
-        UseTreeKind::Simple(rename, id1, id2) => {
-            visit_opt(rename, |rename| vis.visit_ident(rename));
-            vis.visit_id(id1);
-            vis.visit_id(id2);
-        }
+        UseTreeKind::Simple(rename) => visit_opt(rename, |rename| vis.visit_ident(rename)),
         UseTreeKind::Nested(items) => {
             for (tree, id) in items {
                 vis.visit_use_tree(tree);
@@ -740,8 +736,7 @@ pub fn visit_token<T: MutVisitor>(t: &mut Token, vis: &mut T) {
             return; // Avoid visiting the span for the second time.
         }
         token::Interpolated(nt) => {
-            let mut nt = Lrc::make_mut(nt);
-            visit_nonterminal(&mut nt, vis);
+            visit_nonterminal(Lrc::make_mut(nt), vis);
         }
         _ => {}
     }
@@ -1372,6 +1367,7 @@ pub fn noop_visit_expr<T: MutVisitor>(
             fn_decl,
             body,
             fn_decl_span,
+            fn_arg_span: _,
         }) => {
             vis.visit_closure_binder(binder);
             vis.visit_asyncness(asyncness);
index 30481eddf9160ee30009d679ade670127c96fc32..4b2850336a03db2479ec59804de725eb26ff23ae 100644 (file)
@@ -22,7 +22,6 @@
 //!   Moreover, a switch to, e.g., `P<'a, T>` would be easy and mostly automated.
 
 use std::fmt::{self, Debug, Display};
-use std::iter::FromIterator;
 use std::ops::{Deref, DerefMut};
 use std::{slice, vec};
 
index 58c6d397ea2706380e3839f23c4467ee3b47b712..29a5eb4b7c509260a9034296eec158af8abcb123 100644 (file)
@@ -64,7 +64,7 @@ pub fn eq_unspanned(&self, other: &TokenTree) -> bool {
         match (self, other) {
             (TokenTree::Token(token, _), TokenTree::Token(token2, _)) => token.kind == token2.kind,
             (TokenTree::Delimited(_, delim, tts), TokenTree::Delimited(_, delim2, tts2)) => {
-                delim == delim2 && tts.eq_unspanned(&tts2)
+                delim == delim2 && tts.eq_unspanned(tts2)
             }
             _ => false,
         }
@@ -362,7 +362,7 @@ pub fn add_comma(&self) -> Option<(TokenStream, Span)> {
     }
 }
 
-impl iter::FromIterator<TokenTree> for TokenStream {
+impl FromIterator<TokenTree> for TokenStream {
     fn from_iter<I: IntoIterator<Item = TokenTree>>(iter: I) -> Self {
         TokenStream::new(iter.into_iter().collect::<Vec<TokenTree>>())
     }
@@ -402,7 +402,7 @@ pub fn eq_unspanned(&self, other: &TokenStream) -> bool {
         let mut t1 = self.trees();
         let mut t2 = other.trees();
         for (t1, t2) in iter::zip(&mut t1, &mut t2) {
-            if !t1.eq_unspanned(&t2) {
+            if !t1.eq_unspanned(t2) {
                 return false;
             }
         }
@@ -475,7 +475,7 @@ fn flatten_token(token: &Token, spacing: Spacing) -> TokenTree {
             token::Interpolated(nt) => TokenTree::Delimited(
                 DelimSpan::from_single(token.span),
                 Delimiter::Invisible,
-                TokenStream::from_nonterminal_ast(&nt).flattened(),
+                TokenStream::from_nonterminal_ast(nt).flattened(),
             ),
             _ => TokenTree::Token(token.clone(), spacing),
         }
@@ -511,7 +511,7 @@ fn can_skip(stream: &TokenStream) -> bool {
     fn try_glue_to_last(vec: &mut Vec<TokenTree>, tt: &TokenTree) -> bool {
         if let Some(TokenTree::Token(last_tok, Spacing::Joint)) = vec.last()
             && let TokenTree::Token(tok, spacing) = tt
-            && let Some(glued_tok) = last_tok.glue(&tok)
+            && let Some(glued_tok) = last_tok.glue(tok)
         {
             // ...then overwrite the last token tree in `vec` with the
             // glued token, and skip the first token tree from `stream`.
index fbb4cf43a954ccc08814d63fe49b2ec8d2063a10..cdc244c12181d78e6209006a85d4abf71f962660 100644 (file)
@@ -21,6 +21,7 @@ pub fn expr_requires_semi_to_be_stmt(e: &ast::Expr) -> bool {
             | ast::ExprKind::Loop(..)
             | ast::ExprKind::ForLoop(..)
             | ast::ExprKind::TryBlock(..)
+            | ast::ExprKind::ConstBlock(..)
     )
 }
 
index c96474ccb428ae57e6d0ea222299e53ce20d56cd..35454c3a6709224ce20ca3a20d2d915824047895 100644 (file)
@@ -110,7 +110,7 @@ fn get_horizontal_trim<'a>(lines: &'a [&str], kind: CommentKind) -> Option<Strin
         } else {
             &mut lines
         };
-        if let Some(horizontal) = get_horizontal_trim(&lines, kind) {
+        if let Some(horizontal) = get_horizontal_trim(lines, kind) {
             changes = true;
             // remove a "[ \t]*\*" block from each line, if possible
             for line in lines.iter_mut() {
@@ -147,7 +147,7 @@ fn all_whitespace(s: &str, col: CharPos) -> Option<usize> {
 
 fn trim_whitespace_prefix(s: &str, col: CharPos) -> &str {
     let len = s.len();
-    match all_whitespace(&s, col) {
+    match all_whitespace(s, col) {
         Some(col) => {
             if col < len {
                 &s[col..]
index 762fd00e409fb83f544aba8036ce9afb2087e7a0..0daeecb53a8b9d88a1432fa05440360de7096cad 100644 (file)
@@ -72,14 +72,14 @@ pub fn from_token_lit(lit: token::Lit) -> Result<LitKind, LitError> {
                 // new symbol because the string in the LitKind is different to the
                 // string in the token.
                 let s = symbol.as_str();
-                let symbol = if s.contains(&['\\', '\r']) {
+                let symbol = if s.contains(['\\', '\r']) {
                     let mut buf = String::with_capacity(s.len());
                     let mut error = Ok(());
                     // Force-inlining here is aggressive but the closure is
                     // called on every char in the string, so it can be
                     // hot in programs with many long strings.
                     unescape_literal(
-                        &s,
+                        s,
                         Mode::Str,
                         &mut #[inline(always)]
                         |_, unescaped_char| match unescaped_char {
@@ -105,7 +105,7 @@ pub fn from_token_lit(lit: token::Lit) -> Result<LitKind, LitError> {
                     if s.contains('\r') {
                         let mut buf = String::with_capacity(s.len());
                         let mut error = Ok(());
-                        unescape_literal(&s, Mode::RawStr, &mut |_, unescaped_char| {
+                        unescape_literal(s, Mode::RawStr, &mut |_, unescaped_char| {
                             match unescaped_char {
                                 Ok(c) => buf.push(c),
                                 Err(err) => {
@@ -126,7 +126,7 @@ pub fn from_token_lit(lit: token::Lit) -> Result<LitKind, LitError> {
                 let s = symbol.as_str();
                 let mut buf = Vec::with_capacity(s.len());
                 let mut error = Ok(());
-                unescape_literal(&s, Mode::ByteStr, &mut |_, c| match c {
+                unescape_literal(s, Mode::ByteStr, &mut |_, c| match c {
                     Ok(c) => buf.push(byte_from_char(c)),
                     Err(err) => {
                         if err.is_fatal() {
@@ -142,7 +142,7 @@ pub fn from_token_lit(lit: token::Lit) -> Result<LitKind, LitError> {
                 let bytes = if s.contains('\r') {
                     let mut buf = Vec::with_capacity(s.len());
                     let mut error = Ok(());
-                    unescape_literal(&s, Mode::RawByteStr, &mut |_, c| match c {
+                    unescape_literal(s, Mode::RawByteStr, &mut |_, c| match c {
                         Ok(c) => buf.push(byte_from_char(c)),
                         Err(err) => {
                             if err.is_fatal() {
index f65f1f069cba230b790ac60ae97ecbcd3fe94070..819f1884a06922ca5861679de032dde2b2db47a7 100644 (file)
@@ -384,7 +384,7 @@ pub fn contains_exterior_struct_lit(value: &ast::Expr) -> bool {
         | ast::ExprKind::AssignOp(_, lhs, rhs)
         | ast::ExprKind::Binary(_, lhs, rhs) => {
             // X { y: 1 } + X { y: 2 }
-            contains_exterior_struct_lit(&lhs) || contains_exterior_struct_lit(&rhs)
+            contains_exterior_struct_lit(lhs) || contains_exterior_struct_lit(rhs)
         }
         ast::ExprKind::Await(x)
         | ast::ExprKind::Unary(_, x)
@@ -393,12 +393,12 @@ pub fn contains_exterior_struct_lit(value: &ast::Expr) -> bool {
         | ast::ExprKind::Field(x, _)
         | ast::ExprKind::Index(x, _) => {
             // &X { y: 1 }, X { y: 1 }.y
-            contains_exterior_struct_lit(&x)
+            contains_exterior_struct_lit(x)
         }
 
         ast::ExprKind::MethodCall(box ast::MethodCall { receiver, .. }) => {
             // X { y: 1 }.bar(...)
-            contains_exterior_struct_lit(&receiver)
+            contains_exterior_struct_lit(receiver)
         }
 
         _ => false,
index f009f7b300ce0d7d1cf107f5ee9a4aba89473e95..0eae791b25e1c66e8da0b93bdfefa0ce7c5585bb 100644 (file)
@@ -17,7 +17,7 @@ pub fn contains_text_flow_control_chars(s: &str) -> bool {
     // U+2069 - E2 81 A9
     let mut bytes = s.as_bytes();
     loop {
-        match core::slice::memchr::memchr(0xE2, &bytes) {
+        match core::slice::memchr::memchr(0xE2, bytes) {
             Some(idx) => {
                 // bytes are valid UTF-8 -> E2 must be followed by two bytes
                 let ch = &bytes[idx..idx + 3];
index c528118be08085869bac97af434e5f37978784a8..991eb489f6ba3ee115fbf7f8b8dcf691226adf48 100644 (file)
@@ -439,7 +439,7 @@ pub fn walk_path<'a, V: Visitor<'a>>(visitor: &mut V, path: &'a Path) {
 pub fn walk_use_tree<'a, V: Visitor<'a>>(visitor: &mut V, use_tree: &'a UseTree, id: NodeId) {
     visitor.visit_path(&use_tree.prefix, id);
     match &use_tree.kind {
-        UseTreeKind::Simple(rename, ..) => {
+        UseTreeKind::Simple(rename) => {
             // The extra IDs are handled during HIR lowering.
             if let &Some(rename) = rename {
                 visitor.visit_ident(rename);
@@ -840,6 +840,7 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) {
             fn_decl,
             body,
             fn_decl_span: _,
+            fn_arg_span: _,
         }) => {
             visitor.visit_fn(FnKind::Closure(binder, fn_decl, body), expression.span, expression.id)
         }
index 2a0338adc9ca4c51be01dd2aa41de1a2ea0ab054..dfef6ec70fcf772c5f1186200f76709dff5cd5e2 100644 (file)
@@ -222,7 +222,12 @@ pub(crate) fn lower_inline_asm(
                             // Wrap the expression in an AnonConst.
                             let parent_def_id = self.current_hir_id_owner;
                             let node_id = self.next_node_id();
-                            self.create_def(parent_def_id.def_id, node_id, DefPathData::AnonConst);
+                            self.create_def(
+                                parent_def_id.def_id,
+                                node_id,
+                                DefPathData::AnonConst,
+                                *op_sp,
+                            );
                             let anon_const = AnonConst { id: node_id, value: P(expr) };
                             hir::InlineAsmOperand::SymFn {
                                 anon_const: self.lower_anon_const(&anon_const),
index e18bbcf65e719a6467bfd7385f701b0cc0008ad5..3946aab646a1a5b5694b2ed82b2a3039b0dbb3f1 100644 (file)
@@ -16,7 +16,7 @@
 use rustc_hir::definitions::DefPathData;
 use rustc_session::errors::report_lit_error;
 use rustc_span::source_map::{respan, DesugaringKind, Span, Spanned};
-use rustc_span::symbol::{sym, Ident};
+use rustc_span::symbol::{kw, sym, Ident};
 use rustc_span::DUMMY_SP;
 use thin_vec::thin_vec;
 
@@ -147,6 +147,7 @@ pub(super) fn lower_expr_mut(&mut self, e: &Expr) -> hir::Expr<'hir> {
                 ),
                 ExprKind::Async(capture_clause, closure_node_id, block) => self.make_async_expr(
                     *capture_clause,
+                    None,
                     *closure_node_id,
                     None,
                     e.span,
@@ -176,6 +177,7 @@ pub(super) fn lower_expr_mut(&mut self, e: &Expr) -> hir::Expr<'hir> {
                     fn_decl,
                     body,
                     fn_decl_span,
+                    fn_arg_span,
                 }) => {
                     if let Async::Yes { closure_id, .. } = asyncness {
                         self.lower_expr_async_closure(
@@ -186,6 +188,7 @@ pub(super) fn lower_expr_mut(&mut self, e: &Expr) -> hir::Expr<'hir> {
                             fn_decl,
                             body,
                             *fn_decl_span,
+                            *fn_arg_span,
                         )
                     } else {
                         self.lower_expr_closure(
@@ -196,6 +199,7 @@ pub(super) fn lower_expr_mut(&mut self, e: &Expr) -> hir::Expr<'hir> {
                             fn_decl,
                             body,
                             *fn_decl_span,
+                            *fn_arg_span,
                         )
                     }
                 }
@@ -365,7 +369,7 @@ fn lower_legacy_const_generics(
                 let node_id = self.next_node_id();
 
                 // Add a definition for the in-band const def.
-                self.create_def(parent_def_id.def_id, node_id, DefPathData::AnonConst);
+                self.create_def(parent_def_id.def_id, node_id, DefPathData::AnonConst, f.span);
 
                 let anon_const = AnonConst { id: node_id, value: arg };
                 generic_args.push(AngleBracketedArg::Arg(GenericArg::Const(anon_const)));
@@ -432,18 +436,14 @@ fn has_let_expr(expr: &Expr) -> bool {
                 let lhs = self.lower_cond(lhs);
                 let rhs = self.lower_cond(rhs);
 
-                self.arena.alloc(self.expr(
-                    cond.span,
-                    hir::ExprKind::Binary(op, lhs, rhs),
-                    AttrVec::new(),
-                ))
+                self.arena.alloc(self.expr(cond.span, hir::ExprKind::Binary(op, lhs, rhs)))
             }
             ExprKind::Let(..) => self.lower_expr(cond),
             _ => {
                 let cond = self.lower_expr(cond);
                 let reason = DesugaringKind::CondTemporary;
                 let span_block = self.mark_span_with_reason(reason, cond.span, None);
-                self.expr_drop_temps(span_block, cond, AttrVec::new())
+                self.expr_drop_temps(span_block, cond)
             }
         }
     }
@@ -473,12 +473,12 @@ fn lower_expr_while_in_loop_scope(
     ) -> hir::ExprKind<'hir> {
         let lowered_cond = self.with_loop_condition_scope(|t| t.lower_cond(cond));
         let then = self.lower_block_expr(body);
-        let expr_break = self.expr_break(span, AttrVec::new());
+        let expr_break = self.expr_break(span);
         let stmt_break = self.stmt_expr(span, expr_break);
         let else_blk = self.block_all(span, arena_vec![self; stmt_break], None);
-        let else_expr = self.arena.alloc(self.expr_block(else_blk, AttrVec::new()));
+        let else_expr = self.arena.alloc(self.expr_block(else_blk));
         let if_kind = hir::ExprKind::If(lowered_cond, self.arena.alloc(then), Some(else_expr));
-        let if_expr = self.expr(span, if_kind, AttrVec::new());
+        let if_expr = self.expr(span, if_kind);
         let block = self.block_expr(self.arena.alloc(if_expr));
         let span = self.lower_span(span.with_hi(cond.span.hi()));
         let opt_label = self.lower_label(opt_label);
@@ -534,12 +534,7 @@ fn wrap_in_try_constructor(
         expr: &'hir hir::Expr<'hir>,
         overall_span: Span,
     ) -> &'hir hir::Expr<'hir> {
-        let constructor = self.arena.alloc(self.expr_lang_item_path(
-            method_span,
-            lang_item,
-            AttrVec::new(),
-            None,
-        ));
+        let constructor = self.arena.alloc(self.expr_lang_item_path(method_span, lang_item, None));
         self.expr_call(overall_span, constructor, std::slice::from_ref(expr))
     }
 
@@ -581,6 +576,7 @@ fn lower_arm(&mut self, arm: &Arm) -> hir::Arm<'hir> {
     pub(super) fn make_async_expr(
         &mut self,
         capture_clause: CaptureBy,
+        outer_hir_id: Option<hir::HirId>,
         closure_node_id: NodeId,
         ret_ty: Option<hir::FnRetTy<'hir>>,
         span: Span,
@@ -589,14 +585,38 @@ pub(super) fn make_async_expr(
     ) -> hir::ExprKind<'hir> {
         let output = ret_ty.unwrap_or_else(|| hir::FnRetTy::DefaultReturn(self.lower_span(span)));
 
-        // Resume argument type: `ResumeTy`
-        let unstable_span =
-            self.mark_span_with_reason(DesugaringKind::Async, span, self.allow_gen_future.clone());
-        let resume_ty = hir::QPath::LangItem(hir::LangItem::ResumeTy, unstable_span, None);
+        // Resume argument type, which should be `&mut Context<'_>`.
+        // NOTE: Using the `'static` lifetime here is technically cheating.
+        // The `Future::poll` argument really is `&'a mut Context<'b>`, but we cannot
+        // express the fact that we are not storing it across yield-points yet,
+        // and we would thus run into lifetime errors.
+        // See <https://github.com/rust-lang/rust/issues/68923>.
+        // Our lowering makes sure we are not mis-using the `_task_context` input type
+        // in the sense that we are indeed not using it across yield points. We
+        // get a fresh `&mut Context` for each resume / call of `Future::poll`.
+        // This "cheating" was previously done with a `ResumeTy` that contained a raw
+        // pointer, and a `get_context` accessor that pulled the `Context` lifetimes
+        // out of thin air.
+        let context_lifetime_ident = Ident::with_dummy_span(kw::StaticLifetime);
+        let context_lifetime = self.arena.alloc(hir::Lifetime {
+            hir_id: self.next_id(),
+            ident: context_lifetime_ident,
+            res: hir::LifetimeName::Static,
+        });
+        let context_path =
+            hir::QPath::LangItem(hir::LangItem::Context, self.lower_span(span), None);
+        let context_ty = hir::MutTy {
+            ty: self.arena.alloc(hir::Ty {
+                hir_id: self.next_id(),
+                kind: hir::TyKind::Path(context_path),
+                span: self.lower_span(span),
+            }),
+            mutbl: hir::Mutability::Mut,
+        };
         let input_ty = hir::Ty {
             hir_id: self.next_id(),
-            kind: hir::TyKind::Path(resume_ty),
-            span: unstable_span,
+            kind: hir::TyKind::Rptr(context_lifetime, context_ty),
+            span: self.lower_span(span),
         };
 
         // The closure/generator `FnDecl` takes a single (resume) argument of type `input_ty`.
@@ -642,23 +662,23 @@ pub(super) fn make_async_expr(
                 fn_decl,
                 body,
                 fn_decl_span: self.lower_span(span),
+                fn_arg_span: None,
                 movability: Some(hir::Movability::Static),
             });
 
             hir::ExprKind::Closure(c)
         };
-        let parent_has_track_caller = self
-            .attrs
-            .values()
-            .find(|attrs| attrs.into_iter().find(|attr| attr.has_name(sym::track_caller)).is_some())
-            .is_some();
+
+        let track_caller = outer_hir_id
+            .and_then(|id| self.attrs.get(&id.local_id))
+            .map_or(false, |attrs| attrs.into_iter().any(|attr| attr.has_name(sym::track_caller)));
+
+        let hir_id = self.lower_node_id(closure_node_id);
         let unstable_span =
             self.mark_span_with_reason(DesugaringKind::Async, span, self.allow_gen_future.clone());
-
-        let hir_id = if parent_has_track_caller {
-            let generator_hir_id = self.lower_node_id(closure_node_id);
+        if track_caller {
             self.lower_attrs(
-                generator_hir_id,
+                hir_id,
                 &[Attribute {
                     kind: AttrKind::Normal(ptr::P(NormalAttr {
                         item: AttrItem {
@@ -673,10 +693,7 @@ pub(super) fn make_async_expr(
                     span: unstable_span,
                 }],
             );
-            generator_hir_id
-        } else {
-            self.lower_node_id(closure_node_id)
-        };
+        }
 
         let generator = hir::Expr { hir_id, kind: generator_kind, span: self.lower_span(span) };
 
@@ -689,12 +706,8 @@ pub(super) fn make_async_expr(
         // E0700 in src/test/ui/self/self_lifetime-async.rs
 
         // `future::identity_future`:
-        let identity_future = self.expr_lang_item_path(
-            unstable_span,
-            hir::LangItem::IdentityFuture,
-            AttrVec::new(),
-            None,
-        );
+        let identity_future =
+            self.expr_lang_item_path(unstable_span, hir::LangItem::IdentityFuture, None);
 
         // `future::identity_future(generator)`:
         hir::ExprKind::Call(self.arena.alloc(identity_future), arena_vec![self; generator])
@@ -706,7 +719,7 @@ pub(super) fn make_async_expr(
     ///     mut __awaitee => loop {
     ///         match unsafe { ::std::future::Future::poll(
     ///             <::std::pin::Pin>::new_unchecked(&mut __awaitee),
-    ///             ::std::future::get_context(task_context),
+    ///             task_context,
     ///         ) } {
     ///             ::std::task::Poll::Ready(result) => break result,
     ///             ::std::task::Poll::Pending => {}
@@ -747,7 +760,7 @@ fn lower_expr_await(&mut self, dot_await_span: Span, expr: &Expr) -> hir::ExprKi
         // unsafe {
         //     ::std::future::Future::poll(
         //         ::std::pin::Pin::new_unchecked(&mut __awaitee),
-        //         ::std::future::get_context(task_context),
+        //         task_context,
         //     )
         // }
         let poll_expr = {
@@ -765,16 +778,10 @@ fn lower_expr_await(&mut self, dot_await_span: Span, expr: &Expr) -> hir::ExprKi
                 arena_vec![self; ref_mut_awaitee],
                 Some(expr_hir_id),
             );
-            let get_context = self.expr_call_lang_item_fn_mut(
-                gen_future_span,
-                hir::LangItem::GetContext,
-                arena_vec![self; task_context],
-                Some(expr_hir_id),
-            );
             let call = self.expr_call_lang_item_fn(
                 span,
                 hir::LangItem::FuturePoll,
-                arena_vec![self; new_unchecked, get_context],
+                arena_vec![self; new_unchecked, task_context],
                 Some(expr_hir_id),
             );
             self.arena.alloc(self.expr_unsafe(call))
@@ -797,7 +804,7 @@ fn lower_expr_await(&mut self, dot_await_span: Span, expr: &Expr) -> hir::ExprKi
             let break_x = self.with_loop_scope(loop_node_id, move |this| {
                 let expr_break =
                     hir::ExprKind::Break(this.lower_loop_destination(None), Some(x_expr));
-                this.arena.alloc(this.expr(gen_future_span, expr_break, AttrVec::new()))
+                this.arena.alloc(this.expr(gen_future_span, expr_break))
             });
             self.arm(ready_pat, break_x)
         };
@@ -830,17 +837,13 @@ fn lower_expr_await(&mut self, dot_await_span: Span, expr: &Expr) -> hir::ExprKi
             let yield_expr = self.expr(
                 span,
                 hir::ExprKind::Yield(unit, hir::YieldSource::Await { expr: Some(expr_hir_id) }),
-                AttrVec::new(),
             );
             let yield_expr = self.arena.alloc(yield_expr);
 
             if let Some(task_context_hid) = self.task_context {
                 let lhs = self.expr_ident(span, task_context_ident, task_context_hid);
-                let assign = self.expr(
-                    span,
-                    hir::ExprKind::Assign(lhs, yield_expr, self.lower_span(span)),
-                    AttrVec::new(),
-                );
+                let assign =
+                    self.expr(span, hir::ExprKind::Assign(lhs, yield_expr, self.lower_span(span)));
                 self.stmt_expr(span, assign)
             } else {
                 // Use of `await` outside of an async context. Return `yield_expr` so that we can
@@ -898,6 +901,7 @@ fn lower_expr_closure(
         decl: &FnDecl,
         body: &Expr,
         fn_decl_span: Span,
+        fn_arg_span: Span,
     ) -> hir::ExprKind<'hir> {
         let (binder_clause, generic_params) = self.lower_closure_binder(binder);
 
@@ -928,6 +932,7 @@ fn lower_expr_closure(
             fn_decl,
             body: body_id,
             fn_decl_span: self.lower_span(fn_decl_span),
+            fn_arg_span: Some(self.lower_span(fn_arg_span)),
             movability: generator_option,
         });
 
@@ -984,6 +989,7 @@ fn lower_expr_async_closure(
         decl: &FnDecl,
         body: &Expr,
         fn_decl_span: Span,
+        fn_arg_span: Span,
     ) -> hir::ExprKind<'hir> {
         if let &ClosureBinder::For { span, .. } = binder {
             self.tcx.sess.emit_err(NotSupportedForLifetimeBinderAsyncClosure { span });
@@ -1012,13 +1018,16 @@ fn lower_expr_async_closure(
 
                 let async_body = this.make_async_expr(
                     capture_clause,
+                    // FIXME(nbdd0121): This should also use a proper HIR id so `#[track_caller]`
+                    // can be applied on async closures as well.
+                    None,
                     inner_closure_id,
                     async_ret_ty,
                     body.span,
                     hir::AsyncGeneratorKind::Closure,
                     |this| this.with_new_scopes(|this| this.lower_expr_mut(body)),
                 );
-                this.expr(fn_decl_span, async_body, AttrVec::new())
+                this.expr(fn_decl_span, async_body)
             });
             body_id
         });
@@ -1038,6 +1047,7 @@ fn lower_expr_async_closure(
             fn_decl,
             body,
             fn_decl_span: self.lower_span(fn_decl_span),
+            fn_arg_span: Some(self.lower_span(fn_arg_span)),
             movability: None,
         });
         hir::ExprKind::Closure(c)
@@ -1277,7 +1287,7 @@ fn destructure_assign_mut(
         let ident = self.expr_ident(lhs.span, ident, binding);
         let assign =
             hir::ExprKind::Assign(self.lower_expr(lhs), ident, self.lower_span(eq_sign_span));
-        let expr = self.expr(lhs.span, assign, AttrVec::new());
+        let expr = self.expr(lhs.span, assign);
         assignments.push(self.stmt_expr(lhs.span, expr));
         pat
     }
@@ -1318,8 +1328,7 @@ fn lower_expr_range_closed(&mut self, span: Span, e1: &Expr, e2: &Expr) -> hir::
         let e2 = self.lower_expr_mut(e2);
         let fn_path =
             hir::QPath::LangItem(hir::LangItem::RangeInclusiveNew, self.lower_span(span), None);
-        let fn_expr =
-            self.arena.alloc(self.expr(span, hir::ExprKind::Path(fn_path), AttrVec::new()));
+        let fn_expr = self.arena.alloc(self.expr(span, hir::ExprKind::Path(fn_path)));
         hir::ExprKind::Call(fn_expr, arena_vec![self; e1, e2])
     }
 
@@ -1491,8 +1500,7 @@ fn lower_expr_for(
 
         // `None => break`
         let none_arm = {
-            let break_expr =
-                self.with_loop_scope(e.id, |this| this.expr_break_alloc(for_span, AttrVec::new()));
+            let break_expr = self.with_loop_scope(e.id, |this| this.expr_break_alloc(for_span));
             let pat = self.pat_none(for_span);
             self.arm(pat, break_expr)
         };
@@ -1501,7 +1509,7 @@ fn lower_expr_for(
         let some_arm = {
             let some_pat = self.pat_some(pat_span, pat);
             let body_block = self.with_loop_scope(e.id, |this| this.lower_block(body, false));
-            let body_expr = self.arena.alloc(self.expr_block(body_block, AttrVec::new()));
+            let body_expr = self.arena.alloc(self.expr_block(body_block));
             self.arm(some_pat, body_expr)
         };
 
@@ -1564,7 +1572,9 @@ fn lower_expr_for(
         // surrounding scope of the `match` since the `match` is not a terminating scope.
         //
         // Also, add the attributes to the outer returned expr node.
-        self.expr_drop_temps_mut(for_span, match_expr, e.attrs.clone())
+        let expr = self.expr_drop_temps_mut(for_span, match_expr);
+        self.lower_attrs(expr.hir_id, &e.attrs);
+        expr
     }
 
     /// Desugar `ExprKind::Try` from: `<expr>?` into:
@@ -1619,12 +1629,8 @@ fn lower_expr_try(&mut self, span: Span, sub_expr: &Expr) -> hir::ExprKind<'hir>
         let continue_arm = {
             let val_ident = Ident::with_dummy_span(sym::val);
             let (val_pat, val_pat_nid) = self.pat_ident(span, val_ident);
-            let val_expr = self.arena.alloc(self.expr_ident_with_attrs(
-                span,
-                val_ident,
-                val_pat_nid,
-                attrs.clone(),
-            ));
+            let val_expr = self.expr_ident(span, val_ident, val_pat_nid);
+            self.lower_attrs(val_expr.hir_id, &attrs);
             let continue_pat = self.pat_cf_continue(unstable_span, val_pat);
             self.arm(continue_pat, val_expr)
         };
@@ -1650,15 +1656,11 @@ fn lower_expr_try(&mut self, span: Span, sub_expr: &Expr) -> hir::ExprKind<'hir>
                         hir::Destination { label: None, target_id },
                         Some(from_residual_expr),
                     ),
-                    attrs,
                 ))
             } else {
-                self.arena.alloc(self.expr(
-                    try_span,
-                    hir::ExprKind::Ret(Some(from_residual_expr)),
-                    attrs,
-                ))
+                self.arena.alloc(self.expr(try_span, hir::ExprKind::Ret(Some(from_residual_expr))))
             };
+            self.lower_attrs(ret_expr.hir_id, &attrs);
 
             let break_pat = self.pat_cf_break(try_span, residual_local);
             self.arm(break_pat, ret_expr)
@@ -1723,18 +1725,16 @@ pub(super) fn expr_drop_temps(
         &mut self,
         span: Span,
         expr: &'hir hir::Expr<'hir>,
-        attrs: AttrVec,
     ) -> &'hir hir::Expr<'hir> {
-        self.arena.alloc(self.expr_drop_temps_mut(span, expr, attrs))
+        self.arena.alloc(self.expr_drop_temps_mut(span, expr))
     }
 
     pub(super) fn expr_drop_temps_mut(
         &mut self,
         span: Span,
         expr: &'hir hir::Expr<'hir>,
-        attrs: AttrVec,
     ) -> hir::Expr<'hir> {
-        self.expr(span, hir::ExprKind::DropTemps(expr), attrs)
+        self.expr(span, hir::ExprKind::DropTemps(expr))
     }
 
     fn expr_match(
@@ -1744,29 +1744,25 @@ fn expr_match(
         arms: &'hir [hir::Arm<'hir>],
         source: hir::MatchSource,
     ) -> hir::Expr<'hir> {
-        self.expr(span, hir::ExprKind::Match(arg, arms, source), AttrVec::new())
+        self.expr(span, hir::ExprKind::Match(arg, arms, source))
     }
 
-    fn expr_break(&mut self, span: Span, attrs: AttrVec) -> hir::Expr<'hir> {
+    fn expr_break(&mut self, span: Span) -> hir::Expr<'hir> {
         let expr_break = hir::ExprKind::Break(self.lower_loop_destination(None), None);
-        self.expr(span, expr_break, attrs)
+        self.expr(span, expr_break)
     }
 
-    fn expr_break_alloc(&mut self, span: Span, attrs: AttrVec) -> &'hir hir::Expr<'hir> {
-        let expr_break = self.expr_break(span, attrs);
+    fn expr_break_alloc(&mut self, span: Span) -> &'hir hir::Expr<'hir> {
+        let expr_break = self.expr_break(span);
         self.arena.alloc(expr_break)
     }
 
     fn expr_mut_addr_of(&mut self, span: Span, e: &'hir hir::Expr<'hir>) -> hir::Expr<'hir> {
-        self.expr(
-            span,
-            hir::ExprKind::AddrOf(hir::BorrowKind::Ref, hir::Mutability::Mut, e),
-            AttrVec::new(),
-        )
+        self.expr(span, hir::ExprKind::AddrOf(hir::BorrowKind::Ref, hir::Mutability::Mut, e))
     }
 
     fn expr_unit(&mut self, sp: Span) -> &'hir hir::Expr<'hir> {
-        self.arena.alloc(self.expr(sp, hir::ExprKind::Tup(&[]), AttrVec::new()))
+        self.arena.alloc(self.expr(sp, hir::ExprKind::Tup(&[])))
     }
 
     fn expr_call_mut(
@@ -1775,7 +1771,7 @@ fn expr_call_mut(
         e: &'hir hir::Expr<'hir>,
         args: &'hir [hir::Expr<'hir>],
     ) -> hir::Expr<'hir> {
-        self.expr(span, hir::ExprKind::Call(e, args), AttrVec::new())
+        self.expr(span, hir::ExprKind::Call(e, args))
     }
 
     fn expr_call(
@@ -1794,8 +1790,7 @@ fn expr_call_lang_item_fn_mut(
         args: &'hir [hir::Expr<'hir>],
         hir_id: Option<hir::HirId>,
     ) -> hir::Expr<'hir> {
-        let path =
-            self.arena.alloc(self.expr_lang_item_path(span, lang_item, AttrVec::new(), hir_id));
+        let path = self.arena.alloc(self.expr_lang_item_path(span, lang_item, hir_id));
         self.expr_call_mut(span, path, args)
     }
 
@@ -1813,13 +1808,11 @@ fn expr_lang_item_path(
         &mut self,
         span: Span,
         lang_item: hir::LangItem,
-        attrs: AttrVec,
         hir_id: Option<hir::HirId>,
     ) -> hir::Expr<'hir> {
         self.expr(
             span,
             hir::ExprKind::Path(hir::QPath::LangItem(lang_item, self.lower_span(span), hir_id)),
-            attrs,
         )
     }
 
@@ -1833,20 +1826,10 @@ pub(super) fn expr_ident(
     }
 
     pub(super) fn expr_ident_mut(
-        &mut self,
-        sp: Span,
-        ident: Ident,
-        binding: hir::HirId,
-    ) -> hir::Expr<'hir> {
-        self.expr_ident_with_attrs(sp, ident, binding, AttrVec::new())
-    }
-
-    fn expr_ident_with_attrs(
         &mut self,
         span: Span,
         ident: Ident,
         binding: hir::HirId,
-        attrs: AttrVec,
     ) -> hir::Expr<'hir> {
         let hir_id = self.next_id();
         let res = Res::Local(binding);
@@ -1859,7 +1842,7 @@ fn expr_ident_with_attrs(
             }),
         ));
 
-        self.expr(span, expr_path, attrs)
+        self.expr(span, expr_path)
     }
 
     fn expr_unsafe(&mut self, expr: &'hir hir::Expr<'hir>) -> hir::Expr<'hir> {
@@ -1878,32 +1861,21 @@ fn expr_unsafe(&mut self, expr: &'hir hir::Expr<'hir>) -> hir::Expr<'hir> {
                 }),
                 None,
             ),
-            AttrVec::new(),
         )
     }
 
     fn expr_block_empty(&mut self, span: Span) -> &'hir hir::Expr<'hir> {
         let blk = self.block_all(span, &[], None);
-        let expr = self.expr_block(blk, AttrVec::new());
+        let expr = self.expr_block(blk);
         self.arena.alloc(expr)
     }
 
-    pub(super) fn expr_block(
-        &mut self,
-        b: &'hir hir::Block<'hir>,
-        attrs: AttrVec,
-    ) -> hir::Expr<'hir> {
-        self.expr(b.span, hir::ExprKind::Block(b, None), attrs)
+    pub(super) fn expr_block(&mut self, b: &'hir hir::Block<'hir>) -> hir::Expr<'hir> {
+        self.expr(b.span, hir::ExprKind::Block(b, None))
     }
 
-    pub(super) fn expr(
-        &mut self,
-        span: Span,
-        kind: hir::ExprKind<'hir>,
-        attrs: AttrVec,
-    ) -> hir::Expr<'hir> {
+    pub(super) fn expr(&mut self, span: Span, kind: hir::ExprKind<'hir>) -> hir::Expr<'hir> {
         let hir_id = self.next_id();
-        self.lower_attrs(hir_id, &attrs);
         hir::Expr { hir_id, kind, span: self.lower_span(span) }
     }
 
index 2b47e90891291094560afbf51acb84a8467213d7..d73d6d3918ea618dde2c3bbaa77e0954c73f5627 100644 (file)
@@ -19,7 +19,6 @@
 use rustc_span::{Span, Symbol};
 use rustc_target::spec::abi;
 use smallvec::{smallvec, SmallVec};
-use std::iter;
 use thin_vec::ThinVec;
 
 pub(super) struct ItemLowerer<'a, 'hir> {
@@ -179,36 +178,22 @@ pub(super) fn lower_mod(
         let mut node_ids =
             smallvec![hir::ItemId { owner_id: hir::OwnerId { def_id: self.local_def_id(i.id) } }];
         if let ItemKind::Use(use_tree) = &i.kind {
-            self.lower_item_id_use_tree(use_tree, i.id, &mut node_ids);
+            self.lower_item_id_use_tree(use_tree, &mut node_ids);
         }
         node_ids
     }
 
-    fn lower_item_id_use_tree(
-        &mut self,
-        tree: &UseTree,
-        base_id: NodeId,
-        vec: &mut SmallVec<[hir::ItemId; 1]>,
-    ) {
+    fn lower_item_id_use_tree(&mut self, tree: &UseTree, vec: &mut SmallVec<[hir::ItemId; 1]>) {
         match &tree.kind {
             UseTreeKind::Nested(nested_vec) => {
                 for &(ref nested, id) in nested_vec {
                     vec.push(hir::ItemId {
                         owner_id: hir::OwnerId { def_id: self.local_def_id(id) },
                     });
-                    self.lower_item_id_use_tree(nested, id, vec);
-                }
-            }
-            UseTreeKind::Glob => {}
-            UseTreeKind::Simple(_, id1, id2) => {
-                for (_, id) in
-                    iter::zip(self.expect_full_res_from_use(base_id).skip(1), [*id1, *id2])
-                {
-                    vec.push(hir::ItemId {
-                        owner_id: hir::OwnerId { def_id: self.local_def_id(id) },
-                    });
+                    self.lower_item_id_use_tree(nested, vec);
                 }
             }
+            UseTreeKind::Simple(..) | UseTreeKind::Glob => {}
         }
     }
 
@@ -268,8 +253,13 @@ fn lower_item_kind(
                     // only cares about the input argument patterns in the function
                     // declaration (decl), not the return types.
                     let asyncness = header.asyncness;
-                    let body_id =
-                        this.lower_maybe_async_body(span, &decl, asyncness, body.as_deref());
+                    let body_id = this.lower_maybe_async_body(
+                        span,
+                        hir_id,
+                        &decl,
+                        asyncness,
+                        body.as_deref(),
+                    );
 
                     let mut itctx = ImplTraitContext::Universal;
                     let (generics, decl) = this.lower_generics(generics, id, &mut itctx, |this| {
@@ -489,7 +479,7 @@ fn lower_use_tree(
         let segments = prefix.segments.iter().chain(path.segments.iter()).cloned().collect();
 
         match tree.kind {
-            UseTreeKind::Simple(rename, id1, id2) => {
+            UseTreeKind::Simple(rename) => {
                 *ident = tree.ident();
 
                 // First, apply the prefix to the path.
@@ -505,66 +495,16 @@ fn lower_use_tree(
                     }
                 }
 
-                let mut resolutions = self.expect_full_res_from_use(id).fuse();
-                // We want to return *something* from this function, so hold onto the first item
-                // for later.
-                let ret_res = self.lower_res(resolutions.next().unwrap_or(Res::Err));
-
-                // Here, we are looping over namespaces, if they exist for the definition
-                // being imported. We only handle type and value namespaces because we
-                // won't be dealing with macros in the rest of the compiler.
-                // Essentially a single `use` which imports two names is desugared into
-                // two imports.
-                for new_node_id in [id1, id2] {
-                    let new_id = self.local_def_id(new_node_id);
-                    let Some(res) = resolutions.next() else {
-                        debug_assert!(self.children.iter().find(|(id, _)| id == &new_id).is_none());
-                        // Associate an HirId to both ids even if there is no resolution.
-                        self.children.push((
-                            new_id,
-                            hir::MaybeOwner::NonOwner(hir::HirId::make_owner(new_id))),
-                        );
-                        continue;
-                    };
-                    let ident = *ident;
-                    let mut path = path.clone();
-                    for seg in &mut path.segments {
-                        // Give the cloned segment the same resolution information
-                        // as the old one (this is needed for stability checking).
-                        let new_id = self.next_node_id();
-                        self.resolver.clone_res(seg.id, new_id);
-                        seg.id = new_id;
-                    }
-                    let span = path.span;
-
-                    self.with_hir_id_owner(new_node_id, |this| {
-                        let res = this.lower_res(res);
-                        let path = this.lower_path_extra(res, &path, ParamMode::Explicit);
-                        let kind = hir::ItemKind::Use(path, hir::UseKind::Single);
-                        if let Some(attrs) = attrs {
-                            this.attrs.insert(hir::ItemLocalId::new(0), attrs);
-                        }
-
-                        let item = hir::Item {
-                            owner_id: hir::OwnerId { def_id: new_id },
-                            ident: this.lower_ident(ident),
-                            kind,
-                            vis_span,
-                            span: this.lower_span(span),
-                        };
-                        hir::OwnerNode::Item(this.arena.alloc(item))
-                    });
-                }
-
-                let path = self.lower_path_extra(ret_res, &path, ParamMode::Explicit);
+                let res =
+                    self.expect_full_res_from_use(id).map(|res| self.lower_res(res)).collect();
+                let path = self.lower_use_path(res, &path, ParamMode::Explicit);
                 hir::ItemKind::Use(path, hir::UseKind::Single)
             }
             UseTreeKind::Glob => {
-                let path = self.lower_path(
-                    id,
-                    &Path { segments, span: path.span, tokens: None },
-                    ParamMode::Explicit,
-                );
+                let res = self.expect_full_res(id);
+                let res = smallvec![self.lower_res(res)];
+                let path = Path { segments, span: path.span, tokens: None };
+                let path = self.lower_use_path(res, &path, ParamMode::Explicit);
                 hir::ItemKind::Use(path, hir::UseKind::Glob)
             }
             UseTreeKind::Nested(ref trees) => {
@@ -634,9 +574,9 @@ fn lower_use_tree(
                     });
                 }
 
-                let res = self.expect_full_res_from_use(id).next().unwrap_or(Res::Err);
-                let res = self.lower_res(res);
-                let path = self.lower_path_extra(res, &prefix, ParamMode::Explicit);
+                let res =
+                    self.expect_full_res_from_use(id).map(|res| self.lower_res(res)).collect();
+                let path = self.lower_use_path(res, &prefix, ParamMode::Explicit);
                 hir::ItemKind::Use(path, hir::UseKind::ListStem)
             }
         }
@@ -766,6 +706,7 @@ fn lower_field_def(&mut self, (index, f): (usize, &FieldDef)) -> hir::FieldDef<'
 
     fn lower_trait_item(&mut self, i: &AssocItem) -> &'hir hir::TraitItem<'hir> {
         let hir_id = self.lower_node_id(i.id);
+        self.lower_attrs(hir_id, &i.attrs);
         let trait_item_def_id = hir_id.expect_owner();
 
         let (generics, kind, has_default) = match &i.kind {
@@ -789,7 +730,7 @@ fn lower_trait_item(&mut self, i: &AssocItem) -> &'hir hir::TraitItem<'hir> {
             AssocItemKind::Fn(box Fn { sig, generics, body: Some(body), .. }) => {
                 let asyncness = sig.header.asyncness;
                 let body_id =
-                    self.lower_maybe_async_body(i.span, &sig.decl, asyncness, Some(&body));
+                    self.lower_maybe_async_body(i.span, hir_id, &sig.decl, asyncness, Some(&body));
                 let (generics, sig) = self.lower_method_sig(
                     generics,
                     sig,
@@ -824,7 +765,6 @@ fn lower_trait_item(&mut self, i: &AssocItem) -> &'hir hir::TraitItem<'hir> {
             AssocItemKind::MacCall(..) => panic!("macro item shouldn't exist at this point"),
         };
 
-        self.lower_attrs(hir_id, &i.attrs);
         let item = hir::TraitItem {
             owner_id: trait_item_def_id,
             ident: self.lower_ident(i.ident),
@@ -856,13 +796,15 @@ fn lower_trait_item_ref(&mut self, i: &AssocItem) -> hir::TraitItemRef {
 
     /// Construct `ExprKind::Err` for the given `span`.
     pub(crate) fn expr_err(&mut self, span: Span) -> hir::Expr<'hir> {
-        self.expr(span, hir::ExprKind::Err, AttrVec::new())
+        self.expr(span, hir::ExprKind::Err)
     }
 
     fn lower_impl_item(&mut self, i: &AssocItem) -> &'hir hir::ImplItem<'hir> {
         // Since `default impl` is not yet implemented, this is always true in impls.
         let has_value = true;
         let (defaultness, _) = self.lower_defaultness(i.kind.defaultness(), has_value);
+        let hir_id = self.lower_node_id(i.id);
+        self.lower_attrs(hir_id, &i.attrs);
 
         let (generics, kind) = match &i.kind {
             AssocItemKind::Const(_, ty, expr) => {
@@ -875,8 +817,13 @@ fn lower_impl_item(&mut self, i: &AssocItem) -> &'hir hir::ImplItem<'hir> {
             AssocItemKind::Fn(box Fn { sig, generics, body, .. }) => {
                 self.current_item = Some(i.span);
                 let asyncness = sig.header.asyncness;
-                let body_id =
-                    self.lower_maybe_async_body(i.span, &sig.decl, asyncness, body.as_deref());
+                let body_id = self.lower_maybe_async_body(
+                    i.span,
+                    hir_id,
+                    &sig.decl,
+                    asyncness,
+                    body.as_deref(),
+                );
                 let (generics, sig) = self.lower_method_sig(
                     generics,
                     sig,
@@ -909,8 +856,6 @@ fn lower_impl_item(&mut self, i: &AssocItem) -> &'hir hir::ImplItem<'hir> {
             AssocItemKind::MacCall(..) => panic!("`TyMac` should have been expanded by now"),
         };
 
-        let hir_id = self.lower_node_id(i.id);
-        self.lower_attrs(hir_id, &i.attrs);
         let item = hir::ImplItem {
             owner_id: hir_id.expect_owner(),
             ident: self.lower_ident(i.ident),
@@ -1043,6 +988,7 @@ pub(super) fn lower_const_body(&mut self, span: Span, expr: Option<&Expr>) -> hi
     fn lower_maybe_async_body(
         &mut self,
         span: Span,
+        fn_id: hir::HirId,
         decl: &FnDecl,
         asyncness: Async,
         body: Option<&Block>,
@@ -1193,6 +1139,7 @@ fn lower_maybe_async_body(
 
             let async_expr = this.make_async_expr(
                 CaptureBy::Value,
+                Some(fn_id),
                 closure_id,
                 None,
                 body.span,
@@ -1204,11 +1151,8 @@ fn lower_maybe_async_body(
                     // Transform into `drop-temps { <user-body> }`, an expression:
                     let desugared_span =
                         this.mark_span_with_reason(DesugaringKind::Async, user_body.span, None);
-                    let user_body = this.expr_drop_temps(
-                        desugared_span,
-                        this.arena.alloc(user_body),
-                        AttrVec::new(),
-                    );
+                    let user_body =
+                        this.expr_drop_temps(desugared_span, this.arena.alloc(user_body));
 
                     // As noted above, create the final block like
                     //
@@ -1225,14 +1169,11 @@ fn lower_maybe_async_body(
                         Some(user_body),
                     );
 
-                    this.expr_block(body, AttrVec::new())
+                    this.expr_block(body)
                 },
             );
 
-            (
-                this.arena.alloc_from_iter(parameters),
-                this.expr(body.span, async_expr, AttrVec::new()),
-            )
+            (this.arena.alloc_from_iter(parameters), this.expr(body.span, async_expr))
         })
     }
 
index 8e4bfb71336067777a234d9d6267dc7b2e175ca5..d67ede6e1302ef731017cf5f61d9ec7ab56dc87a 100644 (file)
@@ -259,6 +259,8 @@ enum ImplTraitContext {
     },
     /// Impl trait in type aliases.
     TypeAliasesOpaqueTy,
+    /// `impl Trait` is unstably accepted in this position.
+    FeatureGated(ImplTraitPosition, Symbol),
     /// `impl Trait` is not accepted in this position.
     Disallowed(ImplTraitPosition),
 }
@@ -454,8 +456,8 @@ pub fn lower_to_hir<'hir>(tcx: TyCtxt<'hir>, (): ()) -> hir::Crate<'hir> {
     }
 
     // Drop AST to free memory
-    std::mem::drop(ast_index);
-    sess.time("drop_ast", || std::mem::drop(krate));
+    drop(ast_index);
+    sess.time("drop_ast", || drop(krate));
 
     // Discard hygiene data, which isn't required after lowering to HIR.
     if !sess.opts.unstable_opts.keep_hygiene_data {
@@ -487,6 +489,7 @@ fn create_def(
         parent: LocalDefId,
         node_id: ast::NodeId,
         data: DefPathData,
+        span: Span,
     ) -> LocalDefId {
         debug_assert_ne!(node_id, ast::DUMMY_NODE_ID);
         assert!(
@@ -497,7 +500,7 @@ fn create_def(
             self.tcx.hir().def_key(self.local_def_id(node_id)),
         );
 
-        let def_id = self.tcx.create_def(parent, data).def_id();
+        let def_id = self.tcx.at(span).create_def(parent, data).def_id();
 
         debug!("create_def: def_id_to_node_id[{:?}] <-> {:?}", def_id, node_id);
         self.resolver.node_id_to_def_id.insert(node_id, def_id);
@@ -823,6 +826,7 @@ fn lifetime_res_to_generic_param(
                     self.current_hir_id_owner.def_id,
                     param,
                     DefPathData::LifetimeNs(kw::UnderscoreLifetime),
+                    ident.span,
                 );
                 debug!(?_def_id);
 
@@ -1152,15 +1156,16 @@ fn lower_generic_arg(
 
                                 let parent_def_id = self.current_hir_id_owner;
                                 let node_id = self.next_node_id();
+                                let span = self.lower_span(ty.span);
 
                                 // Add a definition for the in-band const def.
                                 let def_id = self.create_def(
                                     parent_def_id.def_id,
                                     node_id,
                                     DefPathData::AnonConst,
+                                    span,
                                 );
 
-                                let span = self.lower_span(ty.span);
                                 let path_expr = Expr {
                                     id: ty.id,
                                     kind: ExprKind::Path(qself.clone(), path.clone()),
@@ -1354,12 +1359,13 @@ fn lower_ty_direct(&mut self, t: &Ty, itctx: &ImplTraitContext) -> hir::Ty<'hir>
                         itctx,
                     ),
                     ImplTraitContext::Universal => {
+                        let span = t.span;
                         self.create_def(
                             self.current_hir_id_owner.def_id,
                             *def_node_id,
                             DefPathData::ImplTrait,
+                            span,
                         );
-                        let span = t.span;
                         let ident = Ident::from_str_and_span(&pprust::ty_to_string(t), span);
                         let (param, bounds, path) =
                             self.lower_generic_and_bounds(*def_node_id, span, ident, bounds);
@@ -1369,17 +1375,15 @@ fn lower_ty_direct(&mut self, t: &Ty, itctx: &ImplTraitContext) -> hir::Ty<'hir>
                         }
                         path
                     }
-                    ImplTraitContext::Disallowed(
-                        position @ (ImplTraitPosition::TraitReturn | ImplTraitPosition::ImplReturn),
-                    ) => {
+                    ImplTraitContext::FeatureGated(position, feature) => {
                         self.tcx
                             .sess
                             .create_feature_err(
                                 MisplacedImplTrait {
                                     span: t.span,
-                                    position: DiagnosticArgFromDisplay(&position),
+                                    position: DiagnosticArgFromDisplay(position),
                                 },
-                                sym::return_position_impl_trait_in_trait,
+                                *feature,
                             )
                             .emit();
                         hir::TyKind::Err
@@ -1387,7 +1391,7 @@ fn lower_ty_direct(&mut self, t: &Ty, itctx: &ImplTraitContext) -> hir::Ty<'hir>
                     ImplTraitContext::Disallowed(position) => {
                         self.tcx.sess.emit_err(MisplacedImplTrait {
                             span: t.span,
-                            position: DiagnosticArgFromDisplay(&position),
+                            position: DiagnosticArgFromDisplay(position),
                         });
                         hir::TyKind::Err
                     }
@@ -1456,6 +1460,7 @@ fn lower_opaque_impl_trait(
             self.current_hir_id_owner.def_id,
             opaque_ty_node_id,
             DefPathData::ImplTrait,
+            opaque_ty_span,
         );
         debug!(?opaque_ty_def_id);
 
@@ -1609,6 +1614,7 @@ fn create_lifetime_defs(
                             parent_def_id,
                             node_id,
                             DefPathData::LifetimeNs(lifetime.ident.name),
+                            lifetime.ident.span,
                         );
                         remapping.insert(old_def_id, new_def_id);
 
@@ -1625,6 +1631,7 @@ fn create_lifetime_defs(
                             parent_def_id,
                             node_id,
                             DefPathData::LifetimeNs(kw::UnderscoreLifetime),
+                            lifetime.ident.span,
                         );
                         remapping.insert(old_def_id, new_def_id);
 
@@ -1733,14 +1740,14 @@ fn lower_fn_decl(
         } else {
             match &decl.output {
                 FnRetTy::Ty(ty) => {
-                    let mut context = if kind.return_impl_trait_allowed(self.tcx) {
+                    let context = if kind.return_impl_trait_allowed(self.tcx) {
                         let fn_def_id = self.local_def_id(fn_node_id);
                         ImplTraitContext::ReturnPositionOpaqueTy {
                             origin: hir::OpaqueTyOrigin::FnReturn(fn_def_id),
                             in_trait: matches!(kind, FnDeclKind::Trait),
                         }
                     } else {
-                        ImplTraitContext::Disallowed(match kind {
+                        let position = match kind {
                             FnDeclKind::Fn | FnDeclKind::Inherent => {
                                 unreachable!("fn should allow in-band lifetimes")
                             }
@@ -1749,9 +1756,16 @@ fn lower_fn_decl(
                             FnDeclKind::Pointer => ImplTraitPosition::PointerReturn,
                             FnDeclKind::Trait => ImplTraitPosition::TraitReturn,
                             FnDeclKind::Impl => ImplTraitPosition::ImplReturn,
-                        })
+                        };
+                        match kind {
+                            FnDeclKind::Trait | FnDeclKind::Impl => ImplTraitContext::FeatureGated(
+                                position,
+                                sym::return_position_impl_trait_in_trait,
+                            ),
+                            _ => ImplTraitContext::Disallowed(position),
+                        }
                     };
-                    hir::FnRetTy::Return(self.lower_ty(ty, &mut context))
+                    hir::FnRetTy::Return(self.lower_ty(ty, &context))
                 }
                 FnRetTy::Default(span) => hir::FnRetTy::DefaultReturn(self.lower_span(*span)),
             }
@@ -1807,7 +1821,7 @@ fn lower_async_fn_ret_ty(
         let fn_def_id = self.local_def_id(fn_node_id);
 
         let opaque_ty_def_id =
-            self.create_def(fn_def_id, opaque_ty_node_id, DefPathData::ImplTrait);
+            self.create_def(fn_def_id, opaque_ty_node_id, DefPathData::ImplTrait, opaque_ty_span);
 
         // When we create the opaque type for this async fn, it is going to have
         // to capture all the lifetimes involved in the signature (including in the
@@ -1867,6 +1881,7 @@ fn lower_async_fn_ret_ty(
                 opaque_ty_def_id,
                 inner_node_id,
                 DefPathData::LifetimeNs(ident.name),
+                ident.span,
             );
             new_remapping.insert(outer_def_id, inner_def_id);
 
@@ -1931,7 +1946,10 @@ fn lower_async_fn_ret_ty(
                     output,
                     span,
                     if in_trait && !this.tcx.features().return_position_impl_trait_in_trait {
-                        ImplTraitContext::Disallowed(ImplTraitPosition::TraitReturn)
+                        ImplTraitContext::FeatureGated(
+                            ImplTraitPosition::TraitReturn,
+                            sym::return_position_impl_trait_in_trait,
+                        )
                     } else {
                         ImplTraitContext::ReturnPositionOpaqueTy {
                             origin: hir::OpaqueTyOrigin::FnReturn(fn_def_id),
@@ -2284,7 +2302,7 @@ fn lower_generic_and_bounds(
     /// has no attributes and is not targeted by a `break`.
     fn lower_block_expr(&mut self, b: &Block) -> hir::Expr<'hir> {
         let block = self.lower_block(b, false);
-        self.expr_block(block, AttrVec::new())
+        self.expr_block(block)
     }
 
     fn lower_array_length(&mut self, c: &AnonConst) -> hir::ArrayLen {
index dc85b5e95ea86d75a73a63cd9e0eaa1d9fb5bd1b..592fc5aa6456f064e0d399f5a0c1487067f147ce 100644 (file)
@@ -9,10 +9,10 @@
 use rustc_hir as hir;
 use rustc_hir::def::{DefKind, PartialRes, Res};
 use rustc_hir::GenericArg;
-use rustc_span::symbol::{kw, Ident};
+use rustc_span::symbol::{kw, sym, Ident};
 use rustc_span::{BytePos, Span, DUMMY_SP};
 
-use smallvec::smallvec;
+use smallvec::{smallvec, SmallVec};
 
 impl<'a, 'hir> LoweringContext<'a, 'hir> {
     #[instrument(level = "trace", skip(self))]
@@ -144,13 +144,13 @@ pub(crate) fn lower_qpath(
         );
     }
 
-    pub(crate) fn lower_path_extra(
+    pub(crate) fn lower_use_path(
         &mut self,
-        res: Res,
+        res: SmallVec<[Res; 3]>,
         p: &Path,
         param_mode: ParamMode,
-    ) -> &'hir hir::Path<'hir> {
-        self.arena.alloc(hir::Path {
+    ) -> &'hir hir::UsePath<'hir> {
+        self.arena.alloc(hir::UsePath {
             res,
             segments: self.arena.alloc_from_iter(p.segments.iter().map(|segment| {
                 self.lower_path_segment(
@@ -165,17 +165,6 @@ pub(crate) fn lower_path_extra(
         })
     }
 
-    pub(crate) fn lower_path(
-        &mut self,
-        id: NodeId,
-        p: &Path,
-        param_mode: ParamMode,
-    ) -> &'hir hir::Path<'hir> {
-        let res = self.expect_full_res(id);
-        let res = self.lower_res(res);
-        self.lower_path_extra(res, p, param_mode)
-    }
-
     pub(crate) fn lower_path_segment(
         &mut self,
         path_span: Span,
@@ -363,11 +352,18 @@ fn lower_parenthesized_parameter_data(
             // fn f(_: impl Fn() -> impl Debug) -> impl Fn() -> impl Debug
             // //      disallowed --^^^^^^^^^^        allowed --^^^^^^^^^^
             // ```
-            FnRetTy::Ty(ty)
-                if matches!(itctx, ImplTraitContext::ReturnPositionOpaqueTy { .. })
-                    && self.tcx.features().impl_trait_in_fn_trait_return =>
-            {
-                self.lower_ty(&ty, itctx)
+            FnRetTy::Ty(ty) if matches!(itctx, ImplTraitContext::ReturnPositionOpaqueTy { .. }) => {
+                if self.tcx.features().impl_trait_in_fn_trait_return {
+                    self.lower_ty(&ty, itctx)
+                } else {
+                    self.lower_ty(
+                        &ty,
+                        &ImplTraitContext::FeatureGated(
+                            ImplTraitPosition::FnTraitReturn,
+                            sym::impl_trait_in_fn_trait_return,
+                        ),
+                    )
+                }
             }
             FnRetTy::Ty(ty) => {
                 self.lower_ty(&ty, &ImplTraitContext::Disallowed(ImplTraitPosition::FnTraitReturn))
index d555cf48730995cb2001f70f0c7c593b2be7a9af..d0e4761a10db8978519b3326d5718ead15bf29b7 100644 (file)
@@ -519,7 +519,7 @@ fn print_meta_item(&mut self, item: &ast::MetaItem) {
             ast::MetaItemKind::List(items) => {
                 self.print_path(&item.path, false, 0);
                 self.popen();
-                self.commasep(Consistent, &items, |s, i| s.print_meta_list_item(i));
+                self.commasep(Consistent, items, |s, i| s.print_meta_list_item(i));
                 self.pclose();
             }
         }
@@ -536,7 +536,7 @@ fn print_meta_item(&mut self, item: &ast::MetaItem) {
     fn print_tt(&mut self, tt: &TokenTree, convert_dollar_crate: bool) {
         match tt {
             TokenTree::Token(token, _) => {
-                let token_str = self.token_to_string_ext(&token, convert_dollar_crate);
+                let token_str = self.token_to_string_ext(token, convert_dollar_crate);
                 self.word(token_str);
                 if let token::DocComment(..) = token.kind {
                     self.hardbreak()
@@ -998,7 +998,7 @@ pub fn print_assoc_constraint(&mut self, constraint: &ast::AssocConstraint) {
             ast::AssocConstraintKind::Bound { bounds } => {
                 if !bounds.is_empty() {
                     self.word_nbsp(":");
-                    self.print_type_bounds(&bounds);
+                    self.print_type_bounds(bounds);
                 }
             }
         }
@@ -1035,7 +1035,7 @@ pub fn print_type(&mut self, ty: &ast::Ty) {
             }
             ast::TyKind::Tup(elts) => {
                 self.popen();
-                self.commasep(Inconsistent, &elts, |s, ty| s.print_type(ty));
+                self.commasep(Inconsistent, elts, |s, ty| s.print_type(ty));
                 if elts.len() == 1 {
                     self.word(",");
                 }
@@ -1254,7 +1254,7 @@ enum AsmArg<'a> {
 
         self.popen();
         self.commasep(Consistent, &args, |s, arg| match arg {
-            AsmArg::Template(template) => s.print_string(&template, ast::StrStyle::Cooked),
+            AsmArg::Template(template) => s.print_string(template, ast::StrStyle::Cooked),
             AsmArg::Operand(op) => {
                 let print_reg_or_class = |s: &mut Self, r: &InlineAsmRegOrRegClass| match r {
                     InlineAsmRegOrRegClass::Reg(r) => s.print_symbol(*r, ast::StrStyle::Cooked),
@@ -1424,11 +1424,11 @@ pub(crate) fn print_pat(&mut self, pat: &ast::Pat) {
                     self.print_path(path, true, 0);
                 }
                 self.popen();
-                self.commasep(Inconsistent, &elts, |s, p| s.print_pat(p));
+                self.commasep(Inconsistent, elts, |s, p| s.print_pat(p));
                 self.pclose();
             }
             PatKind::Or(pats) => {
-                self.strsep("|", true, Inconsistent, &pats, |s, p| s.print_pat(p));
+                self.strsep("|", true, Inconsistent, pats, |s, p| s.print_pat(p));
             }
             PatKind::Path(None, path) => {
                 self.print_path(path, true, 0);
@@ -1450,7 +1450,7 @@ pub(crate) fn print_pat(&mut self, pat: &ast::Pat) {
                 }
                 self.commasep_cmnt(
                     Consistent,
-                    &fields,
+                    fields,
                     |s, f| {
                         s.cbox(INDENT_UNIT);
                         if !f.is_shorthand {
@@ -1475,7 +1475,7 @@ pub(crate) fn print_pat(&mut self, pat: &ast::Pat) {
             }
             PatKind::Tuple(elts) => {
                 self.popen();
-                self.commasep(Inconsistent, &elts, |s, p| s.print_pat(p));
+                self.commasep(Inconsistent, elts, |s, p| s.print_pat(p));
                 if elts.len() == 1 {
                     self.word(",");
                 }
@@ -1498,7 +1498,7 @@ pub(crate) fn print_pat(&mut self, pat: &ast::Pat) {
                     self.print_pat(inner);
                 }
             }
-            PatKind::Lit(e) => self.print_expr(&**e),
+            PatKind::Lit(e) => self.print_expr(e),
             PatKind::Range(begin, end, Spanned { node: end_kind, .. }) => {
                 if let Some(e) = begin {
                     self.print_expr(e);
@@ -1514,7 +1514,7 @@ pub(crate) fn print_pat(&mut self, pat: &ast::Pat) {
             }
             PatKind::Slice(elts) => {
                 self.word("[");
-                self.commasep(Inconsistent, &elts, |s, p| s.print_pat(p));
+                self.commasep(Inconsistent, elts, |s, p| s.print_pat(p));
                 self.word("]");
             }
             PatKind::Rest => self.word(".."),
@@ -1600,7 +1600,7 @@ pub(crate) fn print_generic_params(&mut self, generic_params: &[ast::GenericPara
 
         self.word("<");
 
-        self.commasep(Inconsistent, &generic_params, |s, param| {
+        self.commasep(Inconsistent, generic_params, |s, param| {
             s.print_outer_attributes_inline(&param.attrs);
 
             match &param.kind {
index a00837ec84303d2efe6c9ec3e2e90ff4e62f1369..3b17f6dd627ebb15eeebb66b0ab4d4730b22aeaf 100644 (file)
@@ -307,10 +307,10 @@ pub(super) fn print_expr_outer_attr_style(&mut self, expr: &ast::Expr, is_inline
                 self.print_expr_tup(exprs);
             }
             ast::ExprKind::Call(func, args) => {
-                self.print_expr_call(func, &args);
+                self.print_expr_call(func, args);
             }
             ast::ExprKind::MethodCall(box ast::MethodCall { seg, receiver, args, .. }) => {
-                self.print_expr_method_call(seg, &receiver, &args);
+                self.print_expr_method_call(seg, receiver, args);
             }
             ast::ExprKind::Binary(op, lhs, rhs) => {
                 self.print_expr_binary(*op, lhs, rhs);
@@ -404,6 +404,7 @@ pub(super) fn print_expr_outer_attr_style(&mut self, expr: &ast::Expr, is_inline
                 fn_decl,
                 body,
                 fn_decl_span: _,
+                fn_arg_span: _,
             }) => {
                 self.print_closure_binder(binder);
                 self.print_movability(*movability);
@@ -607,7 +608,7 @@ fn print_closure_binder(&mut self, binder: &ast::ClosureBinder) {
         match binder {
             ast::ClosureBinder::NotPresent => {}
             ast::ClosureBinder::For { generic_params, .. } => {
-                self.print_formal_generic_params(&generic_params)
+                self.print_formal_generic_params(generic_params)
             }
         }
     }
index c52f15401abe3094b9e351344ae5e570bc5c0d6e..5b6a07721e2bbdb605710cfb2a701f5e90078584 100644 (file)
@@ -348,21 +348,10 @@ pub(crate) fn print_item(&mut self, item: &ast::Item) {
                 self.head(visibility_qualified(&item.vis, "trait"));
                 self.print_ident(item.ident);
                 self.print_generic_params(&generics.params);
-                let mut real_bounds = Vec::with_capacity(bounds.len());
-                // FIXME(durka) this seems to be some quite outdated syntax
-                for b in bounds.iter() {
-                    if let GenericBound::Trait(ptr, ast::TraitBoundModifier::Maybe) = b {
-                        self.space();
-                        self.word_space("for ?");
-                        self.print_trait_ref(&ptr.trait_ref);
-                    } else {
-                        real_bounds.push(b.clone());
-                    }
-                }
                 self.nbsp();
-                if !real_bounds.is_empty() {
+                if !bounds.is_empty() {
                     self.word_nbsp("=");
-                    self.print_type_bounds(&real_bounds);
+                    self.print_type_bounds(&bounds);
                 }
                 self.print_where_clause(&generics.where_clause);
                 self.word(";");
@@ -663,7 +652,7 @@ pub fn print_where_predicate(&mut self, predicate: &ast::WherePredicate) {
 
     fn print_use_tree(&mut self, tree: &ast::UseTree) {
         match &tree.kind {
-            ast::UseTreeKind::Simple(rename, ..) => {
+            ast::UseTreeKind::Simple(rename) => {
                 self.print_path(&tree.prefix, false, 0);
                 if let &Some(rename) = rename {
                     self.nbsp();
index 13b48d8f89ab4a6eea6f60a986d88369be7235d4..ab5e19050ead2ffbb0a0d475c69d985ec86fb588 100644 (file)
@@ -277,8 +277,7 @@ fn find_stability_generic<'a, I>(
             allowed_through_unstable_modules = true;
         }
         // attributes with data
-        else if let Some(MetaItem { kind: MetaItemKind::List(ref metas), .. }) = meta {
-            let meta = meta.as_ref().unwrap();
+        else if let Some(meta @ MetaItem { kind: MetaItemKind::List(metas), .. }) = &meta {
             let get = |meta: &MetaItem, item: &mut Option<Symbol>| {
                 if item.is_some() {
                     handle_errors(
@@ -533,25 +532,24 @@ fn find_stability_generic<'a, I>(
 
     // Merge the const-unstable info into the stability info
     if promotable {
-        if let Some((ref mut stab, _)) = const_stab {
-            stab.promotable = promotable;
-        } else {
-            sess.emit_err(session_diagnostics::RustcPromotablePairing { span: item_sp });
+        match &mut const_stab {
+            Some((stab, _)) => stab.promotable = promotable,
+            _ => _ = sess.emit_err(session_diagnostics::RustcPromotablePairing { span: item_sp }),
         }
     }
 
     if allowed_through_unstable_modules {
-        if let Some((
-            Stability {
-                level: StabilityLevel::Stable { ref mut allowed_through_unstable_modules, .. },
-                ..
-            },
-            _,
-        )) = stab
-        {
-            *allowed_through_unstable_modules = true;
-        } else {
-            sess.emit_err(session_diagnostics::RustcAllowedUnstablePairing { span: item_sp });
+        match &mut stab {
+            Some((
+                Stability {
+                    level: StabilityLevel::Stable { allowed_through_unstable_modules, .. },
+                    ..
+                },
+                _,
+            )) => *allowed_through_unstable_modules = true,
+            _ => {
+                sess.emit_err(session_diagnostics::RustcAllowedUnstablePairing { span: item_sp });
+            }
         }
     }
 
@@ -654,8 +652,8 @@ pub fn eval_condition(
     features: Option<&Features>,
     eval: &mut impl FnMut(Condition) -> bool,
 ) -> bool {
-    match cfg.kind {
-        ast::MetaItemKind::List(ref mis) if cfg.name_or_empty() == sym::version => {
+    match &cfg.kind {
+        ast::MetaItemKind::List(mis) if cfg.name_or_empty() == sym::version => {
             try_gate_cfg(sym::version, cfg.span, sess, features);
             let (min_version, span) = match &mis[..] {
                 [NestedMetaItem::Lit(MetaItemLit { kind: LitKind::Str(sym, ..), span, .. })] => {
@@ -688,7 +686,7 @@ pub fn eval_condition(
                 rustc_version >= min_version
             }
         }
-        ast::MetaItemKind::List(ref mis) => {
+        ast::MetaItemKind::List(mis) => {
             for mi in mis.iter() {
                 if !mi.is_meta_item() {
                     handle_errors(
@@ -759,7 +757,7 @@ pub fn eval_condition(
             sess.emit_err(session_diagnostics::CfgPredicateIdentifier { span: cfg.path.span });
             true
         }
-        MetaItemKind::NameValue(ref lit) if !lit.kind.is_str() => {
+        MetaItemKind::NameValue(lit) if !lit.kind.is_str() => {
             handle_errors(
                 sess,
                 lit.span,
@@ -1036,52 +1034,58 @@ pub fn parse_repr_attr(sess: &Session, attr: &Attribute) -> Vec<ReprAttr> {
                     });
                 }
             } else if let Some(meta_item) = item.meta_item() {
-                if let MetaItemKind::NameValue(ref value) = meta_item.kind {
-                    if meta_item.has_name(sym::align) || meta_item.has_name(sym::packed) {
-                        let name = meta_item.name_or_empty().to_ident_string();
-                        recognised = true;
-                        sess.emit_err(session_diagnostics::IncorrectReprFormatGeneric {
-                            span: item.span(),
-                            repr_arg: &name,
-                            cause: IncorrectReprFormatGenericCause::from_lit_kind(
-                                item.span(),
-                                &value.kind,
-                                &name,
-                            ),
-                        });
-                    } else if matches!(
-                        meta_item.name_or_empty(),
-                        sym::C | sym::simd | sym::transparent
-                    ) || int_type_of_word(meta_item.name_or_empty()).is_some()
-                    {
-                        recognised = true;
-                        sess.emit_err(session_diagnostics::InvalidReprHintNoValue {
-                            span: meta_item.span,
-                            name: meta_item.name_or_empty().to_ident_string(),
-                        });
+                match &meta_item.kind {
+                    MetaItemKind::NameValue(value) => {
+                        if meta_item.has_name(sym::align) || meta_item.has_name(sym::packed) {
+                            let name = meta_item.name_or_empty().to_ident_string();
+                            recognised = true;
+                            sess.emit_err(session_diagnostics::IncorrectReprFormatGeneric {
+                                span: item.span(),
+                                repr_arg: &name,
+                                cause: IncorrectReprFormatGenericCause::from_lit_kind(
+                                    item.span(),
+                                    &value.kind,
+                                    &name,
+                                ),
+                            });
+                        } else if matches!(
+                            meta_item.name_or_empty(),
+                            sym::C | sym::simd | sym::transparent
+                        ) || int_type_of_word(meta_item.name_or_empty()).is_some()
+                        {
+                            recognised = true;
+                            sess.emit_err(session_diagnostics::InvalidReprHintNoValue {
+                                span: meta_item.span,
+                                name: meta_item.name_or_empty().to_ident_string(),
+                            });
+                        }
                     }
-                } else if let MetaItemKind::List(_) = meta_item.kind {
-                    if meta_item.has_name(sym::align) {
-                        recognised = true;
-                        sess.emit_err(session_diagnostics::IncorrectReprFormatAlignOneArg {
-                            span: meta_item.span,
-                        });
-                    } else if meta_item.has_name(sym::packed) {
-                        recognised = true;
-                        sess.emit_err(session_diagnostics::IncorrectReprFormatPackedOneOrZeroArg {
-                            span: meta_item.span,
-                        });
-                    } else if matches!(
-                        meta_item.name_or_empty(),
-                        sym::C | sym::simd | sym::transparent
-                    ) || int_type_of_word(meta_item.name_or_empty()).is_some()
-                    {
-                        recognised = true;
-                        sess.emit_err(session_diagnostics::InvalidReprHintNoParen {
-                            span: meta_item.span,
-                            name: meta_item.name_or_empty().to_ident_string(),
-                        });
+                    MetaItemKind::List(_) => {
+                        if meta_item.has_name(sym::align) {
+                            recognised = true;
+                            sess.emit_err(session_diagnostics::IncorrectReprFormatAlignOneArg {
+                                span: meta_item.span,
+                            });
+                        } else if meta_item.has_name(sym::packed) {
+                            recognised = true;
+                            sess.emit_err(
+                                session_diagnostics::IncorrectReprFormatPackedOneOrZeroArg {
+                                    span: meta_item.span,
+                                },
+                            );
+                        } else if matches!(
+                            meta_item.name_or_empty(),
+                            sym::C | sym::simd | sym::transparent
+                        ) || int_type_of_word(meta_item.name_or_empty()).is_some()
+                        {
+                            recognised = true;
+                            sess.emit_err(session_diagnostics::InvalidReprHintNoParen {
+                                span: meta_item.span,
+                                name: meta_item.name_or_empty().to_ident_string(),
+                            });
+                        }
                     }
+                    _ => (),
                 }
             }
             if !recognised {
index 563ff056ae467245b67f5bacee32f7c2b5817ff0..5bb92a3582612f829cadce85e1b52118f4047916 100644 (file)
@@ -198,7 +198,7 @@ fn visit_assign(
         rvalue: &mir::Rvalue<'tcx>,
         location: mir::Location,
     ) {
-        if let mir::Rvalue::Ref(region, kind, ref borrowed_place) = *rvalue {
+        if let &mir::Rvalue::Ref(region, kind, borrowed_place) = rvalue {
             if borrowed_place.ignore_borrow(self.tcx, self.body, &self.locals_state_at_exit) {
                 debug!("ignoring_borrow of {:?}", borrowed_place);
                 return;
@@ -211,7 +211,7 @@ fn visit_assign(
                 region,
                 reserve_location: location,
                 activation_location: TwoPhaseActivation::NotTwoPhase,
-                borrowed_place: *borrowed_place,
+                borrowed_place,
                 assigned_place: *assigned_place,
             };
             let (idx, _) = self.location_map.insert_full(location, borrow);
@@ -273,14 +273,14 @@ fn visit_local(&mut self, temp: Local, context: PlaceContext, location: Location
     }
 
     fn visit_rvalue(&mut self, rvalue: &mir::Rvalue<'tcx>, location: mir::Location) {
-        if let mir::Rvalue::Ref(region, kind, ref place) = *rvalue {
+        if let &mir::Rvalue::Ref(region, kind, place) = rvalue {
             // double-check that we already registered a BorrowData for this
 
             let borrow_data = &self.location_map[&location];
             assert_eq!(borrow_data.reserve_location, location);
             assert_eq!(borrow_data.kind, kind);
             assert_eq!(borrow_data.region, region.to_region_vid());
-            assert_eq!(borrow_data.borrowed_place, *place);
+            assert_eq!(borrow_data.borrowed_place, place);
         }
 
         self.super_rvalue(rvalue, location)
index 8070c0e6710ee0e1288cb9a0284fab5d47f8617f..f825b1d8f70ef502952699fe81e4aecf57edb849 100644 (file)
@@ -358,9 +358,9 @@ fn statement_effect(
         stmt: &mir::Statement<'tcx>,
         location: Location,
     ) {
-        match stmt.kind {
-            mir::StatementKind::Assign(box (lhs, ref rhs)) => {
-                if let mir::Rvalue::Ref(_, _, place) = *rhs {
+        match &stmt.kind {
+            mir::StatementKind::Assign(box (lhs, rhs)) => {
+                if let mir::Rvalue::Ref(_, _, place) = rhs {
                     if place.ignore_borrow(
                         self.tcx,
                         self.body,
@@ -377,13 +377,13 @@ fn statement_effect(
 
                 // Make sure there are no remaining borrows for variables
                 // that are assigned over.
-                self.kill_borrows_on_place(trans, lhs);
+                self.kill_borrows_on_place(trans, *lhs);
             }
 
             mir::StatementKind::StorageDead(local) => {
                 // Make sure there are no remaining borrows for locals that
                 // are gone out of scope.
-                self.kill_borrows_on_place(trans, Place::from(local));
+                self.kill_borrows_on_place(trans, Place::from(*local));
             }
 
             mir::StatementKind::FakeRead(..)
index e05566dc2c745151833d3523ca1b60d6682f964f..1550958ab8eee3942710ba5103fab472f560fa02 100644 (file)
@@ -243,9 +243,9 @@ fn nice_error(
         placeholder_region: ty::Region<'tcx>,
         error_region: Option<ty::Region<'tcx>>,
     ) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>> {
-        let (ref infcx, key, _) =
+        let (infcx, key, _) =
             mbcx.infcx.tcx.infer_ctxt().build_with_canonical(cause.span, &self.canonical_query);
-        let ocx = ObligationCtxt::new(infcx);
+        let ocx = ObligationCtxt::new(&infcx);
         type_op_prove_predicate_with_cause(&ocx, key, cause);
         try_extract_error_from_fulfill_cx(&ocx, placeholder_region, error_region)
     }
@@ -284,9 +284,9 @@ fn nice_error(
         placeholder_region: ty::Region<'tcx>,
         error_region: Option<ty::Region<'tcx>>,
     ) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>> {
-        let (ref infcx, key, _) =
+        let (infcx, key, _) =
             mbcx.infcx.tcx.infer_ctxt().build_with_canonical(cause.span, &self.canonical_query);
-        let ocx = ObligationCtxt::new(infcx);
+        let ocx = ObligationCtxt::new(&infcx);
 
         // FIXME(lqd): Unify and de-duplicate the following with the actual
         // `rustc_traits::type_op::type_op_normalize` query to allow the span we need in the
@@ -328,9 +328,9 @@ fn nice_error(
         placeholder_region: ty::Region<'tcx>,
         error_region: Option<ty::Region<'tcx>>,
     ) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>> {
-        let (ref infcx, key, _) =
+        let (infcx, key, _) =
             mbcx.infcx.tcx.infer_ctxt().build_with_canonical(cause.span, &self.canonical_query);
-        let ocx = ObligationCtxt::new(infcx);
+        let ocx = ObligationCtxt::new(&infcx);
         type_op_ascribe_user_type_with_span(&ocx, key, Some(cause.span)).ok()?;
         try_extract_error_from_fulfill_cx(&ocx, placeholder_region, error_region)
     }
index d221da5c17ed0bd31d20d107933e548b89df2744..5e3745f17353af8543cc8cbdf52dcf7b1e25cfd6 100644 (file)
@@ -265,7 +265,7 @@ pub(crate) fn report_use_of_moved_or_uninitialized(
                 DescribePlaceOpt { including_downcast: true, including_tuple_field: true },
             );
             let note_msg = match opt_name {
-                Some(ref name) => format!("`{}`", name),
+                Some(name) => format!("`{}`", name),
                 None => "value".to_owned(),
             };
             if self.suggest_borrow_fn_like(&mut err, ty, &move_site_vec, &note_msg) {
@@ -1417,7 +1417,7 @@ pub(crate) fn report_borrowed_value_does_not_live_long_enough(
             // then just use the normal error. The closure isn't escaping
             // and `move` will not help here.
             (
-                Some(ref name),
+                Some(name),
                 BorrowExplanation::MustBeValidFor {
                     category:
                         category @ (ConstraintCategory::Return(_)
@@ -1438,7 +1438,7 @@ pub(crate) fn report_borrowed_value_does_not_live_long_enough(
                     &format!("`{}`", name),
                 ),
             (
-                ref name,
+                name,
                 BorrowExplanation::MustBeValidFor {
                     category: ConstraintCategory::Assignment,
                     from_closure: false,
@@ -1450,7 +1450,7 @@ pub(crate) fn report_borrowed_value_does_not_live_long_enough(
                     span,
                     ..
                 },
-            ) => self.report_escaping_data(borrow_span, name, upvar_span, upvar_name, span),
+            ) => self.report_escaping_data(borrow_span, &name, upvar_span, upvar_name, span),
             (Some(name), explanation) => self.report_local_value_does_not_live_long_enough(
                 location,
                 &name,
@@ -2452,7 +2452,7 @@ fn annotate_argument_and_return_for_borrow(
         // and it'll make sense.
         let location = borrow.reserve_location;
         debug!("annotate_argument_and_return_for_borrow: location={:?}", location);
-        if let Some(&Statement { kind: StatementKind::Assign(box (ref reservation, _)), .. }) =
+        if let Some(Statement { kind: StatementKind::Assign(box (reservation, _)), .. }) =
             &self.body[location.block].statements.get(location.statement_index)
         {
             debug!("annotate_argument_and_return_for_borrow: reservation={:?}", reservation);
@@ -2480,8 +2480,8 @@ fn annotate_argument_and_return_for_borrow(
                         // Check if our `target` was captured by a closure.
                         if let Rvalue::Aggregate(
                             box AggregateKind::Closure(def_id, substs),
-                            ref operands,
-                        ) = *rvalue
+                            operands,
+                        ) = rvalue
                         {
                             for operand in operands {
                                 let (Operand::Copy(assigned_from) | Operand::Move(assigned_from)) = operand else {
@@ -2505,7 +2505,7 @@ fn annotate_argument_and_return_for_borrow(
                                 // into a place then we should annotate the closure in
                                 // case it ends up being assigned into the return place.
                                 annotated_closure =
-                                    self.annotate_fn_sig(def_id, substs.as_closure().sig());
+                                    self.annotate_fn_sig(*def_id, substs.as_closure().sig());
                                 debug!(
                                     "annotate_argument_and_return_for_borrow: \
                                      annotated_closure={:?} assigned_from_local={:?} \
index 582d683dd359320679164d3aff5c75991122b2a7..304683618d83ef9dc531c7fcb7f7ed91ed329a7f 100644 (file)
@@ -469,8 +469,8 @@ fn later_use_kind(
                 } else if self.was_captured_by_trait_object(borrow) {
                     LaterUseKind::TraitCapture
                 } else if location.statement_index == block.statements.len() {
-                    if let TerminatorKind::Call { ref func, from_hir_call: true, .. } =
-                        block.terminator().kind
+                    if let TerminatorKind::Call { func, from_hir_call: true, .. } =
+                        &block.terminator().kind
                     {
                         // Just point to the function, to reduce the chance of overlapping spans.
                         let function_span = match func {
@@ -515,19 +515,16 @@ fn was_captured_by_trait_object(&self, borrow: &BorrowData<'tcx>) -> bool {
         // will only ever have one item at any given time, but by using a vector, we can pop from
         // it which simplifies the termination logic.
         let mut queue = vec![location];
-        let mut target = if let Some(&Statement {
-            kind: StatementKind::Assign(box (ref place, _)),
-            ..
-        }) = stmt
-        {
-            if let Some(local) = place.as_local() {
-                local
+        let mut target =
+            if let Some(Statement { kind: StatementKind::Assign(box (place, _)), .. }) = stmt {
+                if let Some(local) = place.as_local() {
+                    local
+                } else {
+                    return false;
+                }
             } else {
                 return false;
-            }
-        } else {
-            return false;
-        };
+            };
 
         debug!("was_captured_by_trait: target={:?} queue={:?}", target, queue);
         while let Some(current_location) = queue.pop() {
index 86c5d9cfa8121c6885338bd6e0e8765795c151bf..4e2271a30672270a5ff8c49c1b4460ab8c11938b 100644 (file)
@@ -78,7 +78,7 @@ pub(super) fn add_moved_or_invoked_closure_note(
             if let StatementKind::Assign(box (into, Rvalue::Use(from))) = &stmt.kind {
                 debug!("add_fnonce_closure_note: into={:?} from={:?}", into, from);
                 match from {
-                    Operand::Copy(ref place) | Operand::Move(ref place)
+                    Operand::Copy(place) | Operand::Move(place)
                         if target == place.local_or_deref_local() =>
                     {
                         target = into.local_or_deref_local()
@@ -101,7 +101,7 @@ pub(super) fn add_moved_or_invoked_closure_note(
                 debug!("add_moved_or_invoked_closure_note: id={:?}", id);
                 if Some(self.infcx.tcx.parent(id)) == self.infcx.tcx.lang_items().fn_once_trait() {
                     let closure = match args.first() {
-                        Some(Operand::Copy(ref place)) | Some(Operand::Move(ref place))
+                        Some(Operand::Copy(place) | Operand::Move(place))
                             if target == place.local_or_deref_local() =>
                         {
                             place.local_or_deref_local().unwrap()
@@ -439,9 +439,9 @@ pub(super) fn borrowed_content_source(
                     if !is_terminator {
                         continue;
                     } else if let Some(Terminator {
-                        kind: TerminatorKind::Call { ref func, from_hir_call: false, .. },
+                        kind: TerminatorKind::Call { func, from_hir_call: false, .. },
                         ..
-                    }) = bbd.terminator
+                    }) = &bbd.terminator
                     {
                         if let Some(source) =
                             BorrowedContentSource::from_call(func.ty(self.body, tcx), tcx)
@@ -811,33 +811,30 @@ pub(super) fn move_spans(
         };
 
         debug!("move_spans: moved_place={:?} location={:?} stmt={:?}", moved_place, location, stmt);
-        if let StatementKind::Assign(box (_, Rvalue::Aggregate(ref kind, ref places))) = stmt.kind {
-            match **kind {
-                AggregateKind::Closure(def_id, _) | AggregateKind::Generator(def_id, _, _) => {
-                    debug!("move_spans: def_id={:?} places={:?}", def_id, places);
-                    if let Some((args_span, generator_kind, capture_kind_span, path_span)) =
-                        self.closure_span(def_id, moved_place, places)
-                    {
-                        return ClosureUse {
-                            generator_kind,
-                            args_span,
-                            capture_kind_span,
-                            path_span,
-                        };
-                    }
-                }
-                _ => {}
+        if let StatementKind::Assign(box (_, Rvalue::Aggregate(kind, places))) = &stmt.kind
+            && let AggregateKind::Closure(def_id, _) | AggregateKind::Generator(def_id, _, _) = **kind
+        {
+            debug!("move_spans: def_id={:?} places={:?}", def_id, places);
+            if let Some((args_span, generator_kind, capture_kind_span, path_span)) =
+                self.closure_span(def_id, moved_place, places)
+            {
+                return ClosureUse {
+                    generator_kind,
+                    args_span,
+                    capture_kind_span,
+                    path_span,
+                };
             }
         }
 
         // StatementKind::FakeRead only contains a def_id if they are introduced as a result
         // of pattern matching within a closure.
-        if let StatementKind::FakeRead(box (cause, ref place)) = stmt.kind {
+        if let StatementKind::FakeRead(box (cause, place)) = stmt.kind {
             match cause {
                 FakeReadCause::ForMatchedPlace(Some(closure_def_id))
                 | FakeReadCause::ForLet(Some(closure_def_id)) => {
                     debug!("move_spans: def_id={:?} place={:?}", closure_def_id, place);
-                    let places = &[Operand::Move(*place)];
+                    let places = &[Operand::Move(place)];
                     if let Some((args_span, generator_kind, capture_kind_span, path_span)) =
                         self.closure_span(closure_def_id, moved_place, places)
                     {
@@ -924,7 +921,7 @@ pub(super) fn borrow_spans(&self, use_span: Span, location: Location) -> UseSpan
         debug!("borrow_spans: use_span={:?} location={:?}", use_span, location);
 
         let target = match self.body[location.block].statements.get(location.statement_index) {
-            Some(&Statement { kind: StatementKind::Assign(box (ref place, _)), .. }) => {
+            Some(Statement { kind: StatementKind::Assign(box (place, _)), .. }) => {
                 if let Some(local) = place.as_local() {
                     local
                 } else {
@@ -940,9 +937,7 @@ pub(super) fn borrow_spans(&self, use_span: Span, location: Location) -> UseSpan
         }
 
         for stmt in &self.body[location.block].statements[location.statement_index + 1..] {
-            if let StatementKind::Assign(box (_, Rvalue::Aggregate(ref kind, ref places))) =
-                stmt.kind
-            {
+            if let StatementKind::Assign(box (_, Rvalue::Aggregate(kind, places))) = &stmt.kind {
                 let (&def_id, is_generator) = match kind {
                     box AggregateKind::Closure(def_id, _) => (def_id, false),
                     box AggregateKind::Generator(def_id, _, _) => (def_id, true),
index 0cf66e41001f84eff9a14acc0a0cb6cce9c0d47f..3319a80681fde277dc0fd3f361c2656adfafe6b6 100644 (file)
@@ -219,8 +219,8 @@ pub(crate) fn report_mutability_error(
             PlaceRef {
                 local,
                 projection:
-                    &[
-                        ref proj_base @ ..,
+                    [
+                        proj_base @ ..,
                         ProjectionElem::Deref,
                         ProjectionElem::Field(field, _),
                         ProjectionElem::Deref,
@@ -231,7 +231,7 @@ pub(crate) fn report_mutability_error(
                 if let Some(span) = get_mut_span_in_struct_field(
                     self.infcx.tcx,
                     Place::ty_from(local, proj_base, self.body, self.infcx.tcx).ty,
-                    field,
+                    *field,
                 ) {
                     err.span_suggestion_verbose(
                         span,
index 7aa099433a76d902145decf600c3fac97be5ded7..9bc2e79e29bc17c9b96a77b7ca99013312159a76 100644 (file)
@@ -921,7 +921,7 @@ fn suggest_move_on_borrowing_closure(&self, diag: &mut Diagnostic) {
                 }
             }
             hir::ExprKind::Block(blk, _) => {
-                if let Some(ref expr) = blk.expr {
+                if let Some(expr) = blk.expr {
                     // only when the block is a closure
                     if let hir::ExprKind::Closure(hir::Closure {
                         capture_clause: hir::CaptureBy::Ref,
index 39173e70acfe93ccab8e84fe763c7555a36de5b6..171e62d91e136463dfd600eb3dc9b51977b6ca59 100644 (file)
@@ -254,7 +254,7 @@ pub(crate) fn give_region_a_name(&self, fr: RegionVid) -> Option<RegionName> {
             .or_else(|| self.give_name_if_anonymous_region_appears_in_impl_signature(fr))
             .or_else(|| self.give_name_if_anonymous_region_appears_in_arg_position_impl_trait(fr));
 
-        if let Some(ref value) = value {
+        if let Some(value) = &value {
             self.region_names.try_borrow_mut().unwrap().insert(fr, value.clone());
         }
 
index f5317a143aed7157d0801da0e688c7bd7a090246..6fd9290058c36383e1a5c155de33f467701ee93d 100644 (file)
@@ -69,9 +69,9 @@ fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) {
                 self.consume_operand(location, op);
             }
             StatementKind::Intrinsic(box NonDivergingIntrinsic::CopyNonOverlapping(mir::CopyNonOverlapping {
-                ref src,
-                ref dst,
-                ref count,
+                src,
+                dst,
+                count,
             })) => {
                 self.consume_operand(location, src);
                 self.consume_operand(location, dst);
@@ -106,7 +106,7 @@ fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location
         self.check_activations(location);
 
         match &terminator.kind {
-            TerminatorKind::SwitchInt { ref discr, switch_ty: _, targets: _ } => {
+            TerminatorKind::SwitchInt { discr, targets: _ } => {
                 self.consume_operand(location, discr);
             }
             TerminatorKind::Drop { place: drop_place, target: _, unwind: _ } => {
@@ -119,7 +119,7 @@ fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location
             }
             TerminatorKind::DropAndReplace {
                 place: drop_place,
-                value: ref new_value,
+                value: new_value,
                 target: _,
                 unwind: _,
             } => {
@@ -127,8 +127,8 @@ fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location
                 self.consume_operand(location, new_value);
             }
             TerminatorKind::Call {
-                ref func,
-                ref args,
+                func,
+                args,
                 destination,
                 target: _,
                 cleanup: _,
@@ -141,15 +141,15 @@ fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location
                 }
                 self.mutate_place(location, *destination, Deep);
             }
-            TerminatorKind::Assert { ref cond, expected: _, ref msg, target: _, cleanup: _ } => {
+            TerminatorKind::Assert { cond, expected: _, msg, target: _, cleanup: _ } => {
                 self.consume_operand(location, cond);
                 use rustc_middle::mir::AssertKind;
-                if let AssertKind::BoundsCheck { ref len, ref index } = *msg {
+                if let AssertKind::BoundsCheck { len, index } = msg {
                     self.consume_operand(location, len);
                     self.consume_operand(location, index);
                 }
             }
-            TerminatorKind::Yield { ref value, resume, resume_arg, drop: _ } => {
+            TerminatorKind::Yield { value, resume, resume_arg, drop: _ } => {
                 self.consume_operand(location, value);
 
                 // Invalidate all borrows of local places
@@ -175,25 +175,25 @@ fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location
             }
             TerminatorKind::InlineAsm {
                 template: _,
-                ref operands,
+                operands,
                 options: _,
                 line_spans: _,
                 destination: _,
                 cleanup: _,
             } => {
                 for op in operands {
-                    match *op {
-                        InlineAsmOperand::In { reg: _, ref value } => {
+                    match op {
+                        InlineAsmOperand::In { reg: _, value } => {
                             self.consume_operand(location, value);
                         }
                         InlineAsmOperand::Out { reg: _, late: _, place, .. } => {
-                            if let Some(place) = place {
+                            if let &Some(place) = place {
                                 self.mutate_place(location, place, Shallow(None));
                             }
                         }
-                        InlineAsmOperand::InOut { reg: _, late: _, ref in_value, out_place } => {
+                        InlineAsmOperand::InOut { reg: _, late: _, in_value, out_place } => {
                             self.consume_operand(location, in_value);
-                            if let Some(out_place) = out_place {
+                            if let &Some(out_place) = out_place {
                                 self.mutate_place(location, out_place, Shallow(None));
                             }
                         }
@@ -252,8 +252,8 @@ fn consume_operand(&mut self, location: Location, operand: &Operand<'tcx>) {
 
     // Simulates consumption of an rvalue
     fn consume_rvalue(&mut self, location: Location, rvalue: &Rvalue<'tcx>) {
-        match *rvalue {
-            Rvalue::Ref(_ /*rgn*/, bk, place) => {
+        match rvalue {
+            &Rvalue::Ref(_ /*rgn*/, bk, place) => {
                 let access_kind = match bk {
                     BorrowKind::Shallow => {
                         (Shallow(Some(ArtificialField::ShallowBorrow)), Read(ReadKind::Borrow(bk)))
@@ -272,7 +272,7 @@ fn consume_rvalue(&mut self, location: Location, rvalue: &Rvalue<'tcx>) {
                 self.access_place(location, place, access_kind, LocalMutationIsAllowed::No);
             }
 
-            Rvalue::AddressOf(mutability, place) => {
+            &Rvalue::AddressOf(mutability, place) => {
                 let access_kind = match mutability {
                     Mutability::Mut => (
                         Deep,
@@ -288,20 +288,19 @@ fn consume_rvalue(&mut self, location: Location, rvalue: &Rvalue<'tcx>) {
 
             Rvalue::ThreadLocalRef(_) => {}
 
-            Rvalue::Use(ref operand)
-            | Rvalue::Repeat(ref operand, _)
-            | Rvalue::UnaryOp(_ /*un_op*/, ref operand)
-            | Rvalue::Cast(_ /*cast_kind*/, ref operand, _ /*ty*/)
-            | Rvalue::ShallowInitBox(ref operand, _ /*ty*/) => {
-                self.consume_operand(location, operand)
-            }
-            Rvalue::CopyForDeref(ref place) => {
-                let op = &Operand::Copy(*place);
+            Rvalue::Use(operand)
+            | Rvalue::Repeat(operand, _)
+            | Rvalue::UnaryOp(_ /*un_op*/, operand)
+            | Rvalue::Cast(_ /*cast_kind*/, operand, _ /*ty*/)
+            | Rvalue::ShallowInitBox(operand, _ /*ty*/) => self.consume_operand(location, operand),
+
+            &Rvalue::CopyForDeref(place) => {
+                let op = &Operand::Copy(place);
                 self.consume_operand(location, op);
             }
 
-            Rvalue::Len(place) | Rvalue::Discriminant(place) => {
-                let af = match *rvalue {
+            &(Rvalue::Len(place) | Rvalue::Discriminant(place)) => {
+                let af = match rvalue {
                     Rvalue::Len(..) => Some(ArtificialField::ArrayLength),
                     Rvalue::Discriminant(..) => None,
                     _ => unreachable!(),
@@ -314,15 +313,15 @@ fn consume_rvalue(&mut self, location: Location, rvalue: &Rvalue<'tcx>) {
                 );
             }
 
-            Rvalue::BinaryOp(_bin_op, box (ref operand1, ref operand2))
-            | Rvalue::CheckedBinaryOp(_bin_op, box (ref operand1, ref operand2)) => {
+            Rvalue::BinaryOp(_bin_op, box (operand1, operand2))
+            | Rvalue::CheckedBinaryOp(_bin_op, box (operand1, operand2)) => {
                 self.consume_operand(location, operand1);
                 self.consume_operand(location, operand2);
             }
 
             Rvalue::NullaryOp(_op, _ty) => {}
 
-            Rvalue::Aggregate(_, ref operands) => {
+            Rvalue::Aggregate(_, operands) => {
                 for operand in operands {
                     self.consume_operand(location, operand);
                 }
index 4d87ecf5e44be224f7a692e233bac2b472d56d51..5289de9b0abf2ffa3d0d2d142904b392070dc2d9 100644 (file)
@@ -578,12 +578,12 @@ fn visit_statement_before_primary_effect(
         self.check_activations(location, span, flow_state);
 
         match &stmt.kind {
-            StatementKind::Assign(box (lhs, ref rhs)) => {
+            StatementKind::Assign(box (lhs, rhs)) => {
                 self.consume_rvalue(location, (rhs, span), flow_state);
 
                 self.mutate_place(location, (*lhs, span), Shallow(None), flow_state);
             }
-            StatementKind::FakeRead(box (_, ref place)) => {
+            StatementKind::FakeRead(box (_, place)) => {
                 // Read for match doesn't access any memory and is used to
                 // assert that a place is safe and live. So we don't have to
                 // do any checks here.
@@ -601,7 +601,7 @@ fn visit_statement_before_primary_effect(
                     flow_state,
                 );
             }
-            StatementKind::Intrinsic(box ref kind) => match kind {
+            StatementKind::Intrinsic(box kind) => match kind {
                 NonDivergingIntrinsic::Assume(op) => self.consume_operand(location, (op, span), flow_state),
                 NonDivergingIntrinsic::CopyNonOverlapping(..) => span_bug!(
                     span,
@@ -643,8 +643,8 @@ fn visit_terminator_before_primary_effect(
 
         self.check_activations(loc, span, flow_state);
 
-        match term.kind {
-            TerminatorKind::SwitchInt { ref discr, switch_ty: _, targets: _ } => {
+        match &term.kind {
+            TerminatorKind::SwitchInt { discr, targets: _ } => {
                 self.consume_operand(loc, (discr, span), flow_state);
             }
             TerminatorKind::Drop { place, target: _, unwind: _ } => {
@@ -656,7 +656,7 @@ fn visit_terminator_before_primary_effect(
 
                 self.access_place(
                     loc,
-                    (place, span),
+                    (*place, span),
                     (AccessDepth::Drop, Write(WriteKind::StorageDeadOrDrop)),
                     LocalMutationIsAllowed::Yes,
                     flow_state,
@@ -664,16 +664,16 @@ fn visit_terminator_before_primary_effect(
             }
             TerminatorKind::DropAndReplace {
                 place: drop_place,
-                value: ref new_value,
+                value: new_value,
                 target: _,
                 unwind: _,
             } => {
-                self.mutate_place(loc, (drop_place, span), Deep, flow_state);
+                self.mutate_place(loc, (*drop_place, span), Deep, flow_state);
                 self.consume_operand(loc, (new_value, span), flow_state);
             }
             TerminatorKind::Call {
-                ref func,
-                ref args,
+                func,
+                args,
                 destination,
                 target: _,
                 cleanup: _,
@@ -684,43 +684,43 @@ fn visit_terminator_before_primary_effect(
                 for arg in args {
                     self.consume_operand(loc, (arg, span), flow_state);
                 }
-                self.mutate_place(loc, (destination, span), Deep, flow_state);
+                self.mutate_place(loc, (*destination, span), Deep, flow_state);
             }
-            TerminatorKind::Assert { ref cond, expected: _, ref msg, target: _, cleanup: _ } => {
+            TerminatorKind::Assert { cond, expected: _, msg, target: _, cleanup: _ } => {
                 self.consume_operand(loc, (cond, span), flow_state);
                 use rustc_middle::mir::AssertKind;
-                if let AssertKind::BoundsCheck { ref len, ref index } = *msg {
+                if let AssertKind::BoundsCheck { len, index } = msg {
                     self.consume_operand(loc, (len, span), flow_state);
                     self.consume_operand(loc, (index, span), flow_state);
                 }
             }
 
-            TerminatorKind::Yield { ref value, resume: _, resume_arg, drop: _ } => {
+            TerminatorKind::Yield { value, resume: _, resume_arg, drop: _ } => {
                 self.consume_operand(loc, (value, span), flow_state);
-                self.mutate_place(loc, (resume_arg, span), Deep, flow_state);
+                self.mutate_place(loc, (*resume_arg, span), Deep, flow_state);
             }
 
             TerminatorKind::InlineAsm {
                 template: _,
-                ref operands,
+                operands,
                 options: _,
                 line_spans: _,
                 destination: _,
                 cleanup: _,
             } => {
                 for op in operands {
-                    match *op {
-                        InlineAsmOperand::In { reg: _, ref value } => {
+                    match op {
+                        InlineAsmOperand::In { reg: _, value } => {
                             self.consume_operand(loc, (value, span), flow_state);
                         }
                         InlineAsmOperand::Out { reg: _, late: _, place, .. } => {
                             if let Some(place) = place {
-                                self.mutate_place(loc, (place, span), Shallow(None), flow_state);
+                                self.mutate_place(loc, (*place, span), Shallow(None), flow_state);
                             }
                         }
-                        InlineAsmOperand::InOut { reg: _, late: _, ref in_value, out_place } => {
+                        InlineAsmOperand::InOut { reg: _, late: _, in_value, out_place } => {
                             self.consume_operand(loc, (in_value, span), flow_state);
-                            if let Some(out_place) = out_place {
+                            if let &Some(out_place) = out_place {
                                 self.mutate_place(
                                     loc,
                                     (out_place, span),
@@ -1164,8 +1164,8 @@ fn consume_rvalue(
         (rvalue, span): (&'cx Rvalue<'tcx>, Span),
         flow_state: &Flows<'cx, 'tcx>,
     ) {
-        match *rvalue {
-            Rvalue::Ref(_ /*rgn*/, bk, place) => {
+        match rvalue {
+            &Rvalue::Ref(_ /*rgn*/, bk, place) => {
                 let access_kind = match bk {
                     BorrowKind::Shallow => {
                         (Shallow(Some(ArtificialField::ShallowBorrow)), Read(ReadKind::Borrow(bk)))
@@ -1203,7 +1203,7 @@ fn consume_rvalue(
                 );
             }
 
-            Rvalue::AddressOf(mutability, place) => {
+            &Rvalue::AddressOf(mutability, place) => {
                 let access_kind = match mutability {
                     Mutability::Mut => (
                         Deep,
@@ -1232,14 +1232,15 @@ fn consume_rvalue(
 
             Rvalue::ThreadLocalRef(_) => {}
 
-            Rvalue::Use(ref operand)
-            | Rvalue::Repeat(ref operand, _)
-            | Rvalue::UnaryOp(_ /*un_op*/, ref operand)
-            | Rvalue::Cast(_ /*cast_kind*/, ref operand, _ /*ty*/)
-            | Rvalue::ShallowInitBox(ref operand, _ /*ty*/) => {
+            Rvalue::Use(operand)
+            | Rvalue::Repeat(operand, _)
+            | Rvalue::UnaryOp(_ /*un_op*/, operand)
+            | Rvalue::Cast(_ /*cast_kind*/, operand, _ /*ty*/)
+            | Rvalue::ShallowInitBox(operand, _ /*ty*/) => {
                 self.consume_operand(location, (operand, span), flow_state)
             }
-            Rvalue::CopyForDeref(place) => {
+
+            &Rvalue::CopyForDeref(place) => {
                 self.access_place(
                     location,
                     (place, span),
@@ -1257,7 +1258,7 @@ fn consume_rvalue(
                 );
             }
 
-            Rvalue::Len(place) | Rvalue::Discriminant(place) => {
+            &(Rvalue::Len(place) | Rvalue::Discriminant(place)) => {
                 let af = match *rvalue {
                     Rvalue::Len(..) => Some(ArtificialField::ArrayLength),
                     Rvalue::Discriminant(..) => None,
@@ -1278,8 +1279,8 @@ fn consume_rvalue(
                 );
             }
 
-            Rvalue::BinaryOp(_bin_op, box (ref operand1, ref operand2))
-            | Rvalue::CheckedBinaryOp(_bin_op, box (ref operand1, ref operand2)) => {
+            Rvalue::BinaryOp(_bin_op, box (operand1, operand2))
+            | Rvalue::CheckedBinaryOp(_bin_op, box (operand1, operand2)) => {
                 self.consume_operand(location, (operand1, span), flow_state);
                 self.consume_operand(location, (operand2, span), flow_state);
             }
@@ -1288,7 +1289,7 @@ fn consume_rvalue(
                 // nullary ops take no dynamic input; no borrowck effect.
             }
 
-            Rvalue::Aggregate(ref aggregate_kind, ref operands) => {
+            Rvalue::Aggregate(aggregate_kind, operands) => {
                 // We need to report back the list of mutable upvars that were
                 // moved into the closure and subsequently used by the closure,
                 // in order to populate our used_mut set.
index 4a12e1b1b92e0f22b180dc566f47f9db2bd989b0..e379e6470623759eabab4567b6d8de519713ba92 100644 (file)
@@ -73,7 +73,7 @@ pub(crate) fn replace_regions_in_mir<'tcx>(
     // Replace all remaining regions with fresh inference variables.
     renumber::renumber_mir(infcx, body, promoted);
 
-    dump_mir(infcx.tcx, None, "renumber", &0, body, |_, _| Ok(()));
+    dump_mir(infcx.tcx, false, "renumber", &0, body, |_, _| Ok(()));
 
     universal_regions
 }
@@ -331,7 +331,7 @@ pub(super) fn dump_mir_results<'tcx>(
         return;
     }
 
-    dump_mir(infcx.tcx, None, "nll", &0, body, |pass_where, out| {
+    dump_mir(infcx.tcx, false, "nll", &0, body, |pass_where, out| {
         match pass_where {
             // Before the CFG, dump out the values for each region variable.
             PassWhere::BeforeCFG => {
@@ -358,15 +358,13 @@ pub(super) fn dump_mir_results<'tcx>(
 
     // Also dump the inference graph constraints as a graphviz file.
     let _: io::Result<()> = try {
-        let mut file =
-            create_dump_file(infcx.tcx, "regioncx.all.dot", None, "nll", &0, body.source)?;
+        let mut file = create_dump_file(infcx.tcx, "regioncx.all.dot", false, "nll", &0, body)?;
         regioncx.dump_graphviz_raw_constraints(&mut file)?;
     };
 
     // Also dump the inference graph constraints as a graphviz file.
     let _: io::Result<()> = try {
-        let mut file =
-            create_dump_file(infcx.tcx, "regioncx.scc.dot", None, "nll", &0, body.source)?;
+        let mut file = create_dump_file(infcx.tcx, "regioncx.scc.dot", false, "nll", &0, body)?;
         regioncx.dump_graphviz_scc_constraints(&mut file)?;
     };
 }
index 1aad6738bba7a01b9081e14508b836bb324190d0..3617bf58be9dd48dd17c18c8738eb566024e18c9 100644 (file)
@@ -121,9 +121,7 @@ pub(super) fn normalize_and_prove_instantiated_predicates(
 
     pub(super) fn prove_predicates(
         &mut self,
-        predicates: impl IntoIterator<
-            Item = impl ToPredicate<'tcx, ty::Predicate<'tcx>> + std::fmt::Debug,
-        >,
+        predicates: impl IntoIterator<Item = impl ToPredicate<'tcx> + std::fmt::Debug>,
         locations: Locations,
         category: ConstraintCategory<'tcx>,
     ) {
@@ -135,7 +133,7 @@ pub(super) fn prove_predicates(
     #[instrument(skip(self), level = "debug")]
     pub(super) fn prove_predicate(
         &mut self,
-        predicate: impl ToPredicate<'tcx, ty::Predicate<'tcx>> + std::fmt::Debug,
+        predicate: impl ToPredicate<'tcx> + std::fmt::Debug,
         locations: Locations,
         category: ConstraintCategory<'tcx>,
     ) {
index 18e3cbbb86a0eace8d8cdd611012ed7b2b1d2041..814bc275019ca0109e4e3d265406630f2cf07398 100644 (file)
@@ -1189,8 +1189,8 @@ fn tcx(&self) -> TyCtxt<'tcx> {
     fn check_stmt(&mut self, body: &Body<'tcx>, stmt: &Statement<'tcx>, location: Location) {
         let tcx = self.tcx();
         debug!("stmt kind: {:?}", stmt.kind);
-        match stmt.kind {
-            StatementKind::Assign(box (ref place, ref rv)) => {
+        match &stmt.kind {
+            StatementKind::Assign(box (place, rv)) => {
                 // Assignments to temporaries are not "interesting";
                 // they are not caused by the user, but rather artifacts
                 // of lowering. Assignments to other sorts of places *are* interesting
@@ -1279,11 +1279,11 @@ fn check_stmt(&mut self, body: &Body<'tcx>, stmt: &Statement<'tcx>, location: Lo
                     );
                 }
             }
-            StatementKind::AscribeUserType(box (ref place, ref projection), variance) => {
+            StatementKind::AscribeUserType(box (place, projection), variance) => {
                 let place_ty = place.ty(body, tcx).ty;
                 if let Err(terr) = self.relate_type_and_user_type(
                     place_ty,
-                    variance,
+                    *variance,
                     projection,
                     Locations::All(stmt.source_info.span),
                     ConstraintCategory::TypeAnnotation,
@@ -1300,7 +1300,7 @@ fn check_stmt(&mut self, body: &Body<'tcx>, stmt: &Statement<'tcx>, location: Lo
                     );
                 }
             }
-            StatementKind::Intrinsic(box ref kind) => match kind {
+            StatementKind::Intrinsic(box kind) => match kind {
                 NonDivergingIntrinsic::Assume(op) => self.check_operand(op, location),
                 NonDivergingIntrinsic::CopyNonOverlapping(..) => span_bug!(
                     stmt.source_info.span,
@@ -1328,7 +1328,7 @@ fn check_terminator(
     ) {
         let tcx = self.tcx();
         debug!("terminator kind: {:?}", term.kind);
-        match term.kind {
+        match &term.kind {
             TerminatorKind::Goto { .. }
             | TerminatorKind::Resume
             | TerminatorKind::Abort
@@ -1342,7 +1342,7 @@ fn check_terminator(
                 // no checks needed for these
             }
 
-            TerminatorKind::DropAndReplace { ref place, ref value, target: _, unwind: _ } => {
+            TerminatorKind::DropAndReplace { place, value, target: _, unwind: _ } => {
                 let place_ty = place.ty(body, tcx).ty;
                 let rv_ty = value.ty(body, tcx);
 
@@ -1360,38 +1360,16 @@ fn check_terminator(
                     );
                 }
             }
-            TerminatorKind::SwitchInt { ref discr, switch_ty, .. } => {
+            TerminatorKind::SwitchInt { discr, .. } => {
                 self.check_operand(discr, term_location);
 
-                let discr_ty = discr.ty(body, tcx);
-                if let Err(terr) = self.sub_types(
-                    discr_ty,
-                    switch_ty,
-                    term_location.to_locations(),
-                    ConstraintCategory::Assignment,
-                ) {
-                    span_mirbug!(
-                        self,
-                        term,
-                        "bad SwitchInt ({:?} on {:?}): {:?}",
-                        switch_ty,
-                        discr_ty,
-                        terr
-                    );
-                }
+                let switch_ty = discr.ty(body, tcx);
                 if !switch_ty.is_integral() && !switch_ty.is_char() && !switch_ty.is_bool() {
                     span_mirbug!(self, term, "bad SwitchInt discr ty {:?}", switch_ty);
                 }
                 // FIXME: check the values
             }
-            TerminatorKind::Call {
-                ref func,
-                ref args,
-                ref destination,
-                from_hir_call,
-                target,
-                ..
-            } => {
+            TerminatorKind::Call { func, args, destination, from_hir_call, target, .. } => {
                 self.check_operand(func, term_location);
                 for arg in args {
                     self.check_operand(arg, term_location);
@@ -1431,7 +1409,7 @@ fn check_terminator(
                     ConstraintCategory::Boring,
                 );
                 let sig = self.normalize(sig, term_location);
-                self.check_call_dest(body, term, &sig, *destination, target, term_location);
+                self.check_call_dest(body, term, &sig, *destination, *target, term_location);
 
                 // The ordinary liveness rules will ensure that all
                 // regions in the type of the callee are live here. We
@@ -1449,9 +1427,9 @@ fn check_terminator(
                         .add_element(region_vid, term_location);
                 }
 
-                self.check_call_inputs(body, term, &sig, args, term_location, from_hir_call);
+                self.check_call_inputs(body, term, &sig, args, term_location, *from_hir_call);
             }
-            TerminatorKind::Assert { ref cond, ref msg, .. } => {
+            TerminatorKind::Assert { cond, msg, .. } => {
                 self.check_operand(cond, term_location);
 
                 let cond_ty = cond.ty(body, tcx);
@@ -1459,7 +1437,7 @@ fn check_terminator(
                     span_mirbug!(self, term, "bad Assert ({:?}, not bool", cond_ty);
                 }
 
-                if let AssertKind::BoundsCheck { ref len, ref index } = *msg {
+                if let AssertKind::BoundsCheck { len, index } = msg {
                     if len.ty(body, tcx) != tcx.types.usize {
                         span_mirbug!(self, len, "bounds-check length non-usize {:?}", len)
                     }
@@ -1468,7 +1446,7 @@ fn check_terminator(
                     }
                 }
             }
-            TerminatorKind::Yield { ref value, .. } => {
+            TerminatorKind::Yield { value, .. } => {
                 self.check_operand(value, term_location);
 
                 let value_ty = value.ty(body, tcx);
@@ -2630,7 +2608,7 @@ fn prove_closure_bounds(
         substs: SubstsRef<'tcx>,
         location: Location,
     ) -> ty::InstantiatedPredicates<'tcx> {
-        if let Some(ref closure_requirements) = tcx.mir_borrowck(def_id).closure_requirements {
+        if let Some(closure_requirements) = &tcx.mir_borrowck(def_id).closure_requirements {
             constraint_conversion::ConstraintConversion::new(
                 self.infcx,
                 self.borrowck_context.universal_regions,
index 618da9e3253252886807c2413eb32a57a5d55af4..a4a0c5b90fed32d2a20372aa908806b81aa9a2fe 100644 (file)
@@ -587,9 +587,9 @@ fn compute_indices(
         let typeck_root_def_id = tcx.typeck_root_def_id(self.mir_def.did.to_def_id());
         let identity_substs = InternalSubsts::identity_for_item(tcx, typeck_root_def_id);
         let fr_substs = match defining_ty {
-            DefiningTy::Closure(_, ref substs)
-            | DefiningTy::Generator(_, ref substs, _)
-            | DefiningTy::InlineConst(_, ref substs) => {
+            DefiningTy::Closure(_, substs)
+            | DefiningTy::Generator(_, substs, _)
+            | DefiningTy::InlineConst(_, substs) => {
                 // In the case of closures, we rely on the fact that
                 // the first N elements in the ClosureSubsts are
                 // inherited from the `typeck_root_def_id`.
index 460175ed2ac84bb35abb7d29181ac418ecb5cd61..95e38e4b053f496604f25079b22722e2fbf3dc4b 100644 (file)
@@ -17,32 +17,23 @@ pub fn expand(
     check_builtin_macro_attribute(ecx, meta_item, sym::alloc_error_handler);
 
     let orig_item = item.clone();
-    let not_function = || {
-        ecx.sess
-            .parse_sess
-            .span_diagnostic
-            .span_err(item.span(), "alloc_error_handler must be a function");
-        vec![orig_item.clone()]
-    };
 
     // Allow using `#[alloc_error_handler]` on an item statement
     // FIXME - if we get deref patterns, use them to reduce duplication here
-    let (item, is_stmt, sig_span) = match &item {
-        Annotatable::Item(item) => match item.kind {
-            ItemKind::Fn(ref fn_kind) => (item, false, ecx.with_def_site_ctxt(fn_kind.sig.span)),
-            _ => return not_function(),
-        },
-        Annotatable::Stmt(stmt) => match &stmt.kind {
-            StmtKind::Item(item_) => match item_.kind {
-                ItemKind::Fn(ref fn_kind) => {
-                    (item_, true, ecx.with_def_site_ctxt(fn_kind.sig.span))
-                }
-                _ => return not_function(),
-            },
-            _ => return not_function(),
-        },
-        _ => return not_function(),
-    };
+    let (item, is_stmt, sig_span) =
+        if let Annotatable::Item(item) = &item
+            && let ItemKind::Fn(fn_kind) = &item.kind
+        {
+            (item, false, ecx.with_def_site_ctxt(fn_kind.sig.span))
+        } else if let Annotatable::Stmt(stmt) = &item
+            && let StmtKind::Item(item) = &stmt.kind
+            && let ItemKind::Fn(fn_kind) = &item.kind
+        {
+            (item, true, ecx.with_def_site_ctxt(fn_kind.sig.span))
+        } else {
+            ecx.sess.parse_sess.span_diagnostic.span_err(item.span(), "alloc_error_handler must be a function");
+            return vec![orig_item.clone()];
+        };
 
     // Generate a bunch of new items using the AllocFnFactory
     let span = ecx.with_def_site_ctxt(item.span);
index bd415901ae34dc7d900b818ba5fd965bc509d89e..93b07801e035d7de24d995980ccd1568063ffb29 100644 (file)
@@ -106,7 +106,7 @@ fn build_initial_imports(&self) -> Stmt {
             (
                 UseTree {
                     prefix: this.cx.path(this.span, vec![Ident::with_dummy_span(sym)]),
-                    kind: UseTreeKind::Simple(None, DUMMY_NODE_ID, DUMMY_NODE_ID),
+                    kind: UseTreeKind::Simple(None),
                     span: this.span,
                 },
                 DUMMY_NODE_ID,
@@ -191,19 +191,19 @@ fn build_panic(&self, expr_str: &str, panic_path: Path) -> P<Expr> {
     ///
     /// See [Self::manage_initial_capture] and [Self::manage_try_capture]
     fn manage_cond_expr(&mut self, expr: &mut P<Expr>) {
-        match (*expr).kind {
-            ExprKind::AddrOf(_, mutability, ref mut local_expr) => {
+        match &mut expr.kind {
+            ExprKind::AddrOf(_, mutability, local_expr) => {
                 self.with_is_consumed_management(
                     matches!(mutability, Mutability::Mut),
                     |this| this.manage_cond_expr(local_expr)
                 );
             }
-            ExprKind::Array(ref mut local_exprs) => {
+            ExprKind::Array(local_exprs) => {
                 for local_expr in local_exprs {
                     self.manage_cond_expr(local_expr);
                 }
             }
-            ExprKind::Binary(ref op, ref mut lhs, ref mut rhs) => {
+            ExprKind::Binary(op, lhs, rhs) => {
                 self.with_is_consumed_management(
                     matches!(
                         op.node,
@@ -226,56 +226,56 @@ fn manage_cond_expr(&mut self, expr: &mut P<Expr>) {
                     }
                 );
             }
-            ExprKind::Call(_, ref mut local_exprs) => {
+            ExprKind::Call(_, local_exprs) => {
                 for local_expr in local_exprs {
                     self.manage_cond_expr(local_expr);
                 }
             }
-            ExprKind::Cast(ref mut local_expr, _) => {
+            ExprKind::Cast(local_expr, _) => {
                 self.manage_cond_expr(local_expr);
             }
-            ExprKind::Index(ref mut prefix, ref mut suffix) => {
+            ExprKind::Index(prefix, suffix) => {
                 self.manage_cond_expr(prefix);
                 self.manage_cond_expr(suffix);
             }
-            ExprKind::MethodCall(ref mut call) => {
-                for arg in call.args.iter_mut() {
+            ExprKind::MethodCall(call) => {
+                for arg in &mut call.args {
                     self.manage_cond_expr(arg);
                 }
             }
-            ExprKind::Path(_, Path { ref segments, .. }) if let &[ref path_segment] = &segments[..] => {
+            ExprKind::Path(_, Path { segments, .. }) if let [path_segment] = &segments[..] => {
                 let path_ident = path_segment.ident;
                 self.manage_initial_capture(expr, path_ident);
             }
-            ExprKind::Paren(ref mut local_expr) => {
+            ExprKind::Paren(local_expr) => {
                 self.manage_cond_expr(local_expr);
             }
-            ExprKind::Range(ref mut prefix, ref mut suffix, _) => {
-                if let Some(ref mut elem) = prefix {
+            ExprKind::Range(prefix, suffix, _) => {
+                if let Some(elem) = prefix {
                     self.manage_cond_expr(elem);
                 }
-                if let Some(ref mut elem) = suffix {
+                if let Some(elem) = suffix {
                     self.manage_cond_expr(elem);
                 }
             }
-            ExprKind::Repeat(ref mut local_expr, ref mut elem) => {
+            ExprKind::Repeat(local_expr, elem) => {
                 self.manage_cond_expr(local_expr);
                 self.manage_cond_expr(&mut elem.value);
             }
-            ExprKind::Struct(ref mut elem) => {
+            ExprKind::Struct(elem) => {
                 for field in &mut elem.fields {
                     self.manage_cond_expr(&mut field.expr);
                 }
-                if let StructRest::Base(ref mut local_expr) = elem.rest {
+                if let StructRest::Base(local_expr) = &mut elem.rest {
                     self.manage_cond_expr(local_expr);
                 }
             }
-            ExprKind::Tup(ref mut local_exprs) => {
+            ExprKind::Tup(local_exprs) => {
                 for local_expr in local_exprs {
                     self.manage_cond_expr(local_expr);
                 }
             }
-            ExprKind::Unary(un_op, ref mut local_expr) => {
+            ExprKind::Unary(un_op, local_expr) => {
                 self.with_is_consumed_management(
                     matches!(un_op, UnOp::Neg | UnOp::Not),
                     |this| this.manage_cond_expr(local_expr)
index d579616ad1b84b25cb77fa516f312fd7ae35ce7b..7da9bdc38a2a8cd3d0b32d031afd5d7ebbf3f3e8 100644 (file)
@@ -4,14 +4,12 @@
 use rustc_session::errors::report_lit_error;
 use rustc_span::symbol::Symbol;
 
-use std::string::String;
-
 pub fn expand_concat(
     cx: &mut base::ExtCtxt<'_>,
     sp: rustc_span::Span,
     tts: TokenStream,
 ) -> Box<dyn base::MacResult + 'static> {
-    let Some(es) = base::get_exprs_from_tts(cx, sp, tts) else {
+    let Some(es) = base::get_exprs_from_tts(cx, tts) else {
         return DummyResult::any(sp);
     };
     let mut accumulator = String::new();
@@ -20,7 +18,7 @@ pub fn expand_concat(
     for e in es {
         match e.kind {
             ast::ExprKind::Lit(token_lit) => match ast::LitKind::from_token_lit(token_lit) {
-                Ok(ast::LitKind::Str(ref s, _) | ast::LitKind::Float(ref s, _)) => {
+                Ok(ast::LitKind::Str(s, _) | ast::LitKind::Float(s, _)) => {
                     accumulator.push_str(s.as_str());
                 }
                 Ok(ast::LitKind::Char(c)) => {
index 56b77fdf58050004dfe41d82d9ca5106b658fcf1..4c424ea430bdf1f0b01872db872944d88b8aea36 100644 (file)
@@ -137,15 +137,15 @@ pub fn expand_concat_bytes(
     sp: rustc_span::Span,
     tts: TokenStream,
 ) -> Box<dyn base::MacResult + 'static> {
-    let Some(es) = base::get_exprs_from_tts(cx, sp, tts) else {
+    let Some(es) = base::get_exprs_from_tts(cx, tts) else {
         return DummyResult::any(sp);
     };
     let mut accumulator = Vec::new();
     let mut missing_literals = vec![];
     let mut has_errors = false;
     for e in es {
-        match e.kind {
-            ast::ExprKind::Array(ref exprs) => {
+        match &e.kind {
+            ast::ExprKind::Array(exprs) => {
                 for expr in exprs {
                     if let Some(elem) =
                         handle_array_element(cx, &mut has_errors, &mut missing_literals, expr)
@@ -154,7 +154,7 @@ pub fn expand_concat_bytes(
                     }
                 }
             }
-            ast::ExprKind::Repeat(ref expr, ref count) => {
+            ast::ExprKind::Repeat(expr, count) => {
                 if let ast::ExprKind::Lit(token_lit) = count.value.kind
                 && let Ok(ast::LitKind::Int(count_val, _)) =
                     ast::LitKind::from_token_lit(token_lit)
@@ -170,7 +170,7 @@ pub fn expand_concat_bytes(
                     cx.span_err(count.value.span, "repeat count is not a positive number");
                 }
             }
-            ast::ExprKind::Lit(token_lit) => match ast::LitKind::from_token_lit(token_lit) {
+            &ast::ExprKind::Lit(token_lit) => match ast::LitKind::from_token_lit(token_lit) {
                 Ok(ast::LitKind::Byte(val)) => {
                     accumulator.push(val);
                 }
@@ -184,7 +184,7 @@ pub fn expand_concat_bytes(
                     has_errors = true;
                 }
             },
-            ast::ExprKind::IncludedBytes(ref bytes) => {
+            ast::ExprKind::IncludedBytes(bytes) => {
                 accumulator.extend_from_slice(bytes);
             }
             ast::ExprKind::Err => {
index 23b96d4176d3a27391d2d5d80491eae91b2b719e..d59b3b8c86d35ef6303bb8a3adbd5e9aecf2d1f1 100644 (file)
@@ -32,10 +32,10 @@ pub fn expand_deriving_clone(
     let bounds;
     let substructure;
     let is_simple;
-    match *item {
-        Annotatable::Item(ref annitem) => match annitem.kind {
-            ItemKind::Struct(_, Generics { ref params, .. })
-            | ItemKind::Enum(_, Generics { ref params, .. }) => {
+    match item {
+        Annotatable::Item(annitem) => match &annitem.kind {
+            ItemKind::Struct(_, Generics { params, .. })
+            | ItemKind::Enum(_, Generics { params, .. }) => {
                 let container_id = cx.current_expansion.id.expn_data().parent.expect_local();
                 let has_derive_copy = cx.resolver.has_derive_copy(container_id);
                 if has_derive_copy
@@ -166,13 +166,13 @@ fn cs_clone(
     };
 
     let vdata;
-    match *substr.fields {
-        Struct(vdata_, ref af) => {
+    match substr.fields {
+        Struct(vdata_, af) => {
             ctor_path = cx.path(trait_span, vec![substr.type_ident]);
             all_fields = af;
-            vdata = vdata_;
+            vdata = *vdata_;
         }
-        EnumMatching(.., variant, ref af) => {
+        EnumMatching(.., variant, af) => {
             ctor_path = cx.path(trait_span, vec![substr.type_ident, variant.ident]);
             all_fields = af;
             vdata = &variant.data;
index 6d14875a9832293f7d238fdd7e525c385b57326a..62af02c2bb4b2d35304cf4eafd42036fba31d5ef 100644 (file)
@@ -78,11 +78,11 @@ fn decodable_substructure(
     let blkarg = Ident::new(sym::_d, trait_span);
     let blkdecoder = cx.expr_ident(trait_span, blkarg);
 
-    let expr = match *substr.fields {
-        StaticStruct(_, ref summary) => {
-            let nfields = match *summary {
-                Unnamed(ref fields, _) => fields.len(),
-                Named(ref fields) => fields.len(),
+    let expr = match substr.fields {
+        StaticStruct(_, summary) => {
+            let nfields = match summary {
+                Unnamed(fields, _) => fields.len(),
+                Named(fields) => fields.len(),
             };
             let fn_read_struct_field_path: Vec<_> =
                 cx.def_site_path(&[sym::rustc_serialize, sym::Decoder, sym::read_struct_field]);
@@ -119,7 +119,7 @@ fn decodable_substructure(
                 ],
             )
         }
-        StaticEnum(_, ref fields) => {
+        StaticEnum(_, fields) => {
             let variant = Ident::new(sym::i, trait_span);
 
             let mut arms = Vec::with_capacity(fields.len() + 1);
@@ -194,10 +194,10 @@ fn decode_static_fields<F>(
 where
     F: FnMut(&mut ExtCtxt<'_>, Span, Symbol, usize) -> P<Expr>,
 {
-    match *fields {
-        Unnamed(ref fields, is_tuple) => {
+    match fields {
+        Unnamed(fields, is_tuple) => {
             let path_expr = cx.expr_path(outer_pat_path);
-            if !is_tuple {
+            if !*is_tuple {
                 path_expr
             } else {
                 let fields = fields
@@ -209,7 +209,7 @@ fn decode_static_fields<F>(
                 cx.expr_call(trait_span, path_expr, fields)
             }
         }
-        Named(ref fields) => {
+        Named(fields) => {
             // use the field's span to get nicer error messages.
             let fields = fields
                 .iter()
index e88d2e409c63b0c95e1e900a7bac12d5e14c4081..eb66c4a69a69bc25bab4126e1649d5f3097a940f 100644 (file)
@@ -62,15 +62,12 @@ fn default_struct_substructure(
     let default_call = |span| cx.expr_call_global(span, default_ident.clone(), Vec::new());
 
     let expr = match summary {
-        Unnamed(ref fields, is_tuple) => {
-            if !is_tuple {
-                cx.expr_ident(trait_span, substr.type_ident)
-            } else {
-                let exprs = fields.iter().map(|sp| default_call(*sp)).collect();
-                cx.expr_call_ident(trait_span, substr.type_ident, exprs)
-            }
+        Unnamed(_, false) => cx.expr_ident(trait_span, substr.type_ident),
+        Unnamed(fields, true) => {
+            let exprs = fields.iter().map(|sp| default_call(*sp)).collect();
+            cx.expr_call_ident(trait_span, substr.type_ident, exprs)
         }
-        Named(ref fields) => {
+        Named(fields) => {
             let default_fields = fields
                 .iter()
                 .map(|&(ident, span)| cx.field_imm(span, ident, default_call(span)))
index 9a46ca815372653ab4696303896d31ea5a34cd5e..68bc0ff2ec0b41c553339586a0874ef5fcb6a1f1 100644 (file)
@@ -164,8 +164,8 @@ fn encodable_substructure(
         ],
     ));
 
-    match *substr.fields {
-        Struct(_, ref fields) => {
+    match substr.fields {
+        Struct(_, fields) => {
             let fn_emit_struct_field_path =
                 cx.def_site_path(&[sym::rustc_serialize, sym::Encoder, sym::emit_struct_field]);
             let mut stmts = Vec::new();
@@ -224,7 +224,7 @@ fn encodable_substructure(
             BlockOrExpr::new_expr(expr)
         }
 
-        EnumMatching(idx, _, variant, ref fields) => {
+        EnumMatching(idx, _, variant, fields) => {
             // We're not generating an AST that the borrow checker is expecting,
             // so we need to generate a unique local variable to take the
             // mutable loan out on, otherwise we get conflicts which don't
@@ -274,7 +274,7 @@ fn encodable_substructure(
                 vec![
                     blkencoder,
                     name,
-                    cx.expr_usize(trait_span, idx),
+                    cx.expr_usize(trait_span, *idx),
                     cx.expr_usize(trait_span, fields.len()),
                     blk,
                 ],
index 7fcaf0b436b9079742bd0261455ae0d613b9ad2f..beac591bfc879065a2c6fd411be0673ba59a3383 100644 (file)
@@ -369,15 +369,14 @@ struct Visitor<'a, 'b> {
 
     impl<'a, 'b> visit::Visitor<'a> for Visitor<'a, 'b> {
         fn visit_ty(&mut self, ty: &'a ast::Ty) {
-            if let ast::TyKind::Path(_, ref path) = ty.kind {
-                if let Some(segment) = path.segments.first() {
-                    if self.ty_param_names.contains(&segment.ident.name) {
-                        self.type_params.push(TypeParameter {
-                            bound_generic_params: self.bound_generic_params_stack.clone(),
-                            ty: P(ty.clone()),
-                        });
-                    }
-                }
+            if let ast::TyKind::Path(_, path) = &ty.kind
+                && let Some(segment) = path.segments.first()
+                && self.ty_param_names.contains(&segment.ident.name)
+            {
+                self.type_params.push(TypeParameter {
+                    bound_generic_params: self.bound_generic_params_stack.clone(),
+                    ty: P(ty.clone()),
+                });
             }
 
             visit::walk_ty(self, ty)
@@ -428,8 +427,8 @@ pub fn expand_ext(
         push: &mut dyn FnMut(Annotatable),
         from_scratch: bool,
     ) {
-        match *item {
-            Annotatable::Item(ref item) => {
+        match item {
+            Annotatable::Item(item) => {
                 let is_packed = item.attrs.iter().any(|attr| {
                     for r in attr::find_repr_attrs(&cx.sess, attr) {
                         if let attr::ReprPacked(_) = r {
@@ -438,10 +437,10 @@ pub fn expand_ext(
                     }
                     false
                 });
-                let has_no_type_params = match item.kind {
-                    ast::ItemKind::Struct(_, ref generics)
-                    | ast::ItemKind::Enum(_, ref generics)
-                    | ast::ItemKind::Union(_, ref generics) => !generics
+                let has_no_type_params = match &item.kind {
+                    ast::ItemKind::Struct(_, generics)
+                    | ast::ItemKind::Enum(_, generics)
+                    | ast::ItemKind::Union(_, generics) => !generics
                         .params
                         .iter()
                         .any(|param| matches!(param.kind, ast::GenericParamKind::Type { .. })),
@@ -451,8 +450,8 @@ pub fn expand_ext(
                 let copy_fields =
                     is_packed && has_no_type_params && cx.resolver.has_derive_copy(container_id);
 
-                let newitem = match item.kind {
-                    ast::ItemKind::Struct(ref struct_def, ref generics) => self.expand_struct_def(
+                let newitem = match &item.kind {
+                    ast::ItemKind::Struct(struct_def, generics) => self.expand_struct_def(
                         cx,
                         &struct_def,
                         item.ident,
@@ -460,7 +459,7 @@ pub fn expand_ext(
                         from_scratch,
                         copy_fields,
                     ),
-                    ast::ItemKind::Enum(ref enum_def, ref generics) => {
+                    ast::ItemKind::Enum(enum_def, generics) => {
                         // We ignore `is_packed` here, because `repr(packed)`
                         // enums cause an error later on.
                         //
@@ -468,7 +467,7 @@ pub fn expand_ext(
                         // downstream in blatantly illegal code, so it is fine.
                         self.expand_enum_def(cx, enum_def, item.ident, generics, from_scratch)
                     }
-                    ast::ItemKind::Union(ref struct_def, ref generics) => {
+                    ast::ItemKind::Union(struct_def, generics) => {
                         if self.supports_unions {
                             self.expand_struct_def(
                                 cx,
@@ -663,12 +662,11 @@ fn create_derived_impl(
 
                     for field_ty_param in field_ty_params {
                         // if we have already handled this type, skip it
-                        if let ast::TyKind::Path(_, ref p) = field_ty_param.ty.kind {
-                            if p.segments.len() == 1
-                                && ty_param_names.contains(&p.segments[0].ident.name)
-                            {
-                                continue;
-                            };
+                        if let ast::TyKind::Path(_, p) = &field_ty_param.ty.kind
+                            && let [sole_segment] = &*p.segments
+                            && ty_param_names.contains(&sole_segment.ident.name)
+                        {
+                            continue;
                         }
                         let mut bounds: Vec<_> = self
                             .additional_bounds
index 36e2e29308694741deece6a0106b538a29ddc8b3..eaa4881906a8e3aed446cec6b99657d64972d02f 100644 (file)
@@ -115,7 +115,7 @@ pub fn to_path(
         self_ty: Ident,
         generics: &Generics,
     ) -> ast::Path {
-        match *self {
+        match self {
             Self_ => {
                 let params: Vec<_> = generics
                     .params
@@ -135,7 +135,7 @@ pub fn to_path(
 
                 cx.path_all(span, false, vec![self_ty], params)
             }
-            Path(ref p) => p.to_path(cx, span, self_ty, generics),
+            Path(p) => p.to_path(cx, span, self_ty, generics),
             Ref(..) => cx.span_bug(span, "ref in a path in generic `derive`"),
             Unit => cx.span_bug(span, "unit in a path in generic `derive`"),
         }
@@ -180,10 +180,7 @@ pub fn to_generics(
         let params = self
             .bounds
             .iter()
-            .map(|t| {
-                let (name, ref bounds) = *t;
-                mk_ty_param(cx, span, name, &bounds, self_ty, self_generics)
-            })
+            .map(|&(name, ref bounds)| mk_ty_param(cx, span, name, &bounds, self_ty, self_generics))
             .collect();
 
         Generics {
index 13fdd4fa68c43cd1e70c3683c6ed6db7a5cd7e12..de657e4e6006dcd8aea6ce578dd2657242a488b2 100644 (file)
@@ -125,12 +125,12 @@ fn inject_impl_of_structural_trait(
     structural_path: generic::ty::Path,
     push: &mut dyn FnMut(Annotatable),
 ) {
-    let Annotatable::Item(ref item) = *item else {
+    let Annotatable::Item(item) = item else {
         unreachable!();
     };
 
-    let generics = match item.kind {
-        ItemKind::Struct(_, ref generics) | ItemKind::Enum(_, ref generics) => generics,
+    let generics = match &item.kind {
+        ItemKind::Struct(_, generics) | ItemKind::Enum(_, generics) => generics,
         // Do not inject `impl Structural for Union`. (`PartialEq` does not
         // support unions, so we will see error downstream.)
         ItemKind::Union(..) => return,
index b8828fa671a5ddbc30a21e130a7923fc6282842f..a7283ea601b19e4c20a846beb76663562001da0f 100644 (file)
@@ -52,8 +52,8 @@ pub fn expand_env<'cx>(
     sp: Span,
     tts: TokenStream,
 ) -> Box<dyn base::MacResult + 'cx> {
-    let mut exprs = match get_exprs_from_tts(cx, sp, tts) {
-        Some(ref exprs) if exprs.is_empty() => {
+    let mut exprs = match get_exprs_from_tts(cx, tts) {
+        Some(exprs) if exprs.is_empty() => {
             cx.span_err(sp, "env! takes 1 or 2 arguments");
             return DummyResult::any(sp);
         }
index 8b07c110663572175c42f3da08ef5740f1ff639d..63bc0d552c11e7e24e17bbb45ff095590fd1f18b 100644 (file)
@@ -333,7 +333,7 @@ enum ArgRef<'a> {
             parse::Piece::String(s) => {
                 unfinished_literal.push_str(s);
             }
-            parse::Piece::NextArgument(parse::Argument { position, position_span, format }) => {
+            parse::Piece::NextArgument(box parse::Argument { position, position_span, format }) => {
                 if !unfinished_literal.is_empty() {
                     template.push(FormatArgsPiece::Literal(Symbol::intern(&unfinished_literal)));
                     unfinished_literal.clear();
index ecd16736e7c302e4a518113e20d0c29604b5d718..6f7fc3a95ba640e21311aca2d37b403f0f25a2c4 100644 (file)
@@ -13,23 +13,23 @@ pub enum Substitution<'a> {
 
     impl<'a> Substitution<'a> {
         pub fn as_str(&self) -> &str {
-            match *self {
-                Substitution::Format(ref fmt) => fmt.span,
+            match self {
+                Substitution::Format(fmt) => fmt.span,
                 Substitution::Escape(_) => "%%",
             }
         }
 
         pub fn position(&self) -> Option<InnerSpan> {
-            match *self {
-                Substitution::Format(ref fmt) => Some(fmt.position),
-                Substitution::Escape((start, end)) => Some(InnerSpan::new(start, end)),
+            match self {
+                Substitution::Format(fmt) => Some(fmt.position),
+                &Substitution::Escape((start, end)) => Some(InnerSpan::new(start, end)),
             }
         }
 
         pub fn set_position(&mut self, start: usize, end: usize) {
             match self {
-                Substitution::Format(ref mut fmt) => fmt.position = InnerSpan::new(start, end),
-                Substitution::Escape(ref mut pos) => *pos = (start, end),
+                Substitution::Format(fmt) => fmt.position = InnerSpan::new(start, end),
+                Substitution::Escape(pos) => *pos = (start, end),
             }
         }
 
@@ -38,8 +38,8 @@ pub fn set_position(&mut self, start: usize, end: usize) {
         /// This ignores cases where the substitution does not have an exact equivalent, or where
         /// the substitution would be unnecessary.
         pub fn translate(&self) -> Result<String, Option<String>> {
-            match *self {
-                Substitution::Format(ref fmt) => fmt.translate(),
+            match self {
+                Substitution::Format(fmt) => fmt.translate(),
                 Substitution::Escape(_) => Err(None),
             }
         }
@@ -635,23 +635,17 @@ pub fn as_str(&self) -> String {
         }
 
         pub fn position(&self) -> Option<InnerSpan> {
-            match self {
-                Substitution::Ordinal(_, pos)
-                | Substitution::Name(_, pos)
-                | Substitution::Escape(pos) => Some(InnerSpan::new(pos.0, pos.1)),
-            }
+            let (Self::Ordinal(_, pos) | Self::Name(_, pos) | Self::Escape(pos)) = self;
+            Some(InnerSpan::new(pos.0, pos.1))
         }
 
         pub fn set_position(&mut self, start: usize, end: usize) {
-            match self {
-                Substitution::Ordinal(_, ref mut pos)
-                | Substitution::Name(_, ref mut pos)
-                | Substitution::Escape(ref mut pos) => *pos = (start, end),
-            }
+            let (Self::Ordinal(_, pos) | Self::Name(_, pos) | Self::Escape(pos)) = self;
+            *pos = (start, end);
         }
 
         pub fn translate(&self) -> Result<String, Option<String>> {
-            match *self {
+            match self {
                 Substitution::Ordinal(n, _) => Ok(format!("{{{}}}", n)),
                 Substitution::Name(n, _) => Ok(format!("{{{}}}", n)),
                 Substitution::Escape(_) => Err(None),
index 0817aed037ef814aab672a3f132da1b57f2c865b..41531580c1987ca92c0a2e76c10dc993c1c7e16a 100644 (file)
@@ -20,27 +20,23 @@ pub fn expand(
     check_builtin_macro_attribute(ecx, meta_item, sym::global_allocator);
 
     let orig_item = item.clone();
-    let not_static = || {
-        ecx.sess.parse_sess.span_diagnostic.span_err(item.span(), "allocators must be statics");
-        vec![orig_item.clone()]
-    };
 
     // Allow using `#[global_allocator]` on an item statement
     // FIXME - if we get deref patterns, use them to reduce duplication here
-    let (item, is_stmt, ty_span) = match &item {
-        Annotatable::Item(item) => match item.kind {
-            ItemKind::Static(ref ty, ..) => (item, false, ecx.with_def_site_ctxt(ty.span)),
-            _ => return not_static(),
-        },
-        Annotatable::Stmt(stmt) => match &stmt.kind {
-            StmtKind::Item(item_) => match item_.kind {
-                ItemKind::Static(ref ty, ..) => (item_, true, ecx.with_def_site_ctxt(ty.span)),
-                _ => return not_static(),
-            },
-            _ => return not_static(),
-        },
-        _ => return not_static(),
-    };
+    let (item, is_stmt, ty_span) =
+        if let Annotatable::Item(item) = &item
+            && let ItemKind::Static(ty, ..) = &item.kind
+        {
+            (item, false, ecx.with_def_site_ctxt(ty.span))
+        } else if let Annotatable::Stmt(stmt) = &item
+            && let StmtKind::Item(item) = &stmt.kind
+            && let ItemKind::Static(ty, ..) = &item.kind
+        {
+            (item, true, ecx.with_def_site_ctxt(ty.span))
+        } else {
+            ecx.sess.parse_sess.span_diagnostic.span_err(item.span(), "allocators must be statics");
+            return vec![orig_item.clone()]
+        };
 
     // Generate a bunch of new items using the AllocFnFactory
     let span = ecx.with_def_site_ctxt(item.span);
index 1cbbfb432647cebca15bfa72ac207eac463fb1da..75cfac723848502729b868cc6bdb96f2018252af 100644 (file)
@@ -45,6 +45,7 @@
 mod source_util;
 mod test;
 mod trace_macros;
+mod type_ascribe;
 mod util;
 
 pub mod asm;
@@ -92,6 +93,7 @@ pub fn register_builtin_macros(resolver: &mut dyn ResolverExpand) {
         unreachable: edition_panic::expand_unreachable,
         stringify: source_util::expand_stringify,
         trace_macros: trace_macros::expand_trace_macros,
+        type_ascribe: type_ascribe::expand_type_ascribe,
     }
 
     register_attr! {
index 3bcb60478efbc58db96665ce497c42373806fac3..f5f02fc772ab6b5b08b1082ab3fdb8ee6ec99f3c 100644 (file)
@@ -466,61 +466,67 @@ fn test_type(cx: &ExtCtxt<'_>) -> TestType {
 fn has_test_signature(cx: &ExtCtxt<'_>, i: &ast::Item) -> bool {
     let has_should_panic_attr = cx.sess.contains_name(&i.attrs, sym::should_panic);
     let sd = &cx.sess.parse_sess.span_diagnostic;
-    if let ast::ItemKind::Fn(box ast::Fn { ref sig, ref generics, .. }) = i.kind {
-        if let ast::Unsafe::Yes(span) = sig.header.unsafety {
-            sd.struct_span_err(i.span, "unsafe functions cannot be used for tests")
-                .span_label(span, "`unsafe` because of this")
-                .emit();
-            return false;
-        }
-        if let ast::Async::Yes { span, .. } = sig.header.asyncness {
-            sd.struct_span_err(i.span, "async functions cannot be used for tests")
-                .span_label(span, "`async` because of this")
-                .emit();
-            return false;
-        }
-
-        // If the termination trait is active, the compiler will check that the output
-        // type implements the `Termination` trait as `libtest` enforces that.
-        let has_output = match sig.decl.output {
-            ast::FnRetTy::Default(..) => false,
-            ast::FnRetTy::Ty(ref t) if t.kind.is_unit() => false,
-            _ => true,
-        };
-
-        if !sig.decl.inputs.is_empty() {
-            sd.span_err(i.span, "functions used as tests can not have any arguments");
-            return false;
-        }
+    match &i.kind {
+        ast::ItemKind::Fn(box ast::Fn { sig, generics, .. }) => {
+            if let ast::Unsafe::Yes(span) = sig.header.unsafety {
+                sd.struct_span_err(i.span, "unsafe functions cannot be used for tests")
+                    .span_label(span, "`unsafe` because of this")
+                    .emit();
+                return false;
+            }
+            if let ast::Async::Yes { span, .. } = sig.header.asyncness {
+                sd.struct_span_err(i.span, "async functions cannot be used for tests")
+                    .span_label(span, "`async` because of this")
+                    .emit();
+                return false;
+            }
 
-        match (has_output, has_should_panic_attr) {
-            (true, true) => {
-                sd.span_err(i.span, "functions using `#[should_panic]` must return `()`");
-                false
+            // If the termination trait is active, the compiler will check that the output
+            // type implements the `Termination` trait as `libtest` enforces that.
+            let has_output = match &sig.decl.output {
+                ast::FnRetTy::Default(..) => false,
+                ast::FnRetTy::Ty(t) if t.kind.is_unit() => false,
+                _ => true,
+            };
+
+            if !sig.decl.inputs.is_empty() {
+                sd.span_err(i.span, "functions used as tests can not have any arguments");
+                return false;
             }
-            (true, false) => {
-                if !generics.params.is_empty() {
-                    sd.span_err(i.span, "functions used as tests must have signature fn() -> ()");
+
+            match (has_output, has_should_panic_attr) {
+                (true, true) => {
+                    sd.span_err(i.span, "functions using `#[should_panic]` must return `()`");
                     false
-                } else {
-                    true
                 }
+                (true, false) => {
+                    if !generics.params.is_empty() {
+                        sd.span_err(
+                            i.span,
+                            "functions used as tests must have signature fn() -> ()",
+                        );
+                        false
+                    } else {
+                        true
+                    }
+                }
+                (false, _) => true,
             }
-            (false, _) => true,
         }
-    } else {
-        // should be unreachable because `is_test_fn_item` should catch all non-fn items
-        false
+        _ => {
+            // should be unreachable because `is_test_fn_item` should catch all non-fn items
+            debug_assert!(false);
+            false
+        }
     }
 }
 
 fn has_bench_signature(cx: &ExtCtxt<'_>, i: &ast::Item) -> bool {
-    let has_sig = if let ast::ItemKind::Fn(box ast::Fn { ref sig, .. }) = i.kind {
+    let has_sig = match &i.kind {
         // N.B., inadequate check, but we're running
         // well before resolve, can't get too deep.
-        sig.decl.inputs.len() == 1
-    } else {
-        false
+        ast::ItemKind::Fn(box ast::Fn { sig, .. }) => sig.decl.inputs.len() == 1,
+        _ => false,
     };
 
     if !has_sig {
index b5bce9278a907311d22e90493dba96dff9aee7b2..ad8871080910640e11e123b8f27221101f2a543d 100644 (file)
@@ -131,8 +131,9 @@ fn visit_crate(&mut self, c: &mut ast::Crate) {
 
         // We don't want to recurse into anything other than mods, since
         // mods or tests inside of functions will break things
-        if let ast::ItemKind::Mod(_, ModKind::Loaded(.., ref spans)) = item.kind {
-            let ast::ModSpans { inner_span: span, inject_use_span: _ } = *spans;
+        if let ast::ItemKind::Mod(_, ModKind::Loaded(.., ast::ModSpans { inner_span: span, .. })) =
+            item.kind
+        {
             let prev_tests = mem::take(&mut self.tests);
             noop_visit_item_kind(&mut item.kind, self);
             self.add_test_cases(item.id, span, prev_tests);
diff --git a/compiler/rustc_builtin_macros/src/type_ascribe.rs b/compiler/rustc_builtin_macros/src/type_ascribe.rs
new file mode 100644 (file)
index 0000000..72b85af
--- /dev/null
@@ -0,0 +1,35 @@
+use rustc_ast::ptr::P;
+use rustc_ast::tokenstream::TokenStream;
+use rustc_ast::{token, Expr, ExprKind, Ty};
+use rustc_errors::PResult;
+use rustc_expand::base::{self, DummyResult, ExtCtxt, MacEager};
+use rustc_span::Span;
+
+pub fn expand_type_ascribe(
+    cx: &mut ExtCtxt<'_>,
+    span: Span,
+    tts: TokenStream,
+) -> Box<dyn base::MacResult + 'static> {
+    let (expr, ty) = match parse_ascribe(cx, tts) {
+        Ok(parsed) => parsed,
+        Err(mut err) => {
+            err.emit();
+            return DummyResult::any(span);
+        }
+    };
+
+    let asc_expr = cx.expr(span, ExprKind::Type(expr, ty));
+
+    return MacEager::expr(asc_expr);
+}
+
+fn parse_ascribe<'a>(cx: &mut ExtCtxt<'a>, stream: TokenStream) -> PResult<'a, (P<Expr>, P<Ty>)> {
+    let mut parser = cx.new_parser_from_tts(stream);
+
+    let expr = parser.parse_expr()?;
+    parser.expect(&token::Comma)?;
+
+    let ty = parser.parse_ty()?;
+
+    Ok((expr, ty))
+}
index 3fa9d56cd01a381549991ed9fca4940e2b925d08..3b406036c356e9e3023964f049184a2d1f0121f5 100644 (file)
@@ -19,11 +19,6 @@ version = "1.0.60"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "c794e162a5eff65c72ef524dfe393eb923c354e350bb78b9c7383df13f3bc142"
 
-[[package]]
-name = "ar"
-version = "0.8.0"
-source = "git+https://github.com/bjorn3/rust-ar.git?branch=do_not_remove_cg_clif_ranlib#de9ab0e56bf3a208381d342aa5b60f9ff2891648"
-
 [[package]]
 name = "arrayvec"
 version = "0.7.2"
@@ -324,7 +319,6 @@ dependencies = [
 name = "rustc_codegen_cranelift"
 version = "0.1.0"
 dependencies = [
- "ar",
  "cranelift-codegen",
  "cranelift-frontend",
  "cranelift-jit",
index 09cf5b4a1edd8482ef98d33c5aeb295600947b6a..0fdd5de118ccb10cb4db0776c5ca9c69b19cc07f 100644 (file)
@@ -18,7 +18,6 @@ target-lexicon = "0.12.0"
 gimli = { version = "0.26.0", default-features = false, features = ["write"]}
 object = { version = "0.29.0", default-features = false, features = ["std", "read_core", "write", "archive", "coff", "elf", "macho", "pe"] }
 
-ar = { git = "https://github.com/bjorn3/rust-ar.git", branch = "do_not_remove_cg_clif_ranlib" }
 indexmap = "1.9.1"
 libloading = { version = "0.7.3", optional = true }
 once_cell = "1.10.0"
index f2e3bf16e61842bae2d73b66ac42c0cec2a01e6e..5a29bc18def549cd035bb0a1144b5cab54addef4 100644 (file)
@@ -1,35 +1,15 @@
-//! Creation of ar archives like for the lib and staticlib crate type
-
-use std::collections::BTreeMap;
-use std::fs::File;
-use std::io::{self, Read, Seek};
 use std::path::{Path, PathBuf};
 
-use rustc_codegen_ssa::back::archive::{ArchiveBuilder, ArchiveBuilderBuilder};
+use rustc_codegen_ssa::back::archive::{
+    get_native_object_symbols, ArArchiveBuilder, ArchiveBuilder, ArchiveBuilderBuilder,
+};
 use rustc_session::Session;
 
-use object::read::archive::ArchiveFile;
-use object::{Object, ObjectSymbol, ReadCache};
-
-#[derive(Debug)]
-enum ArchiveEntry {
-    FromArchive { archive_index: usize, file_range: (u64, u64) },
-    File(PathBuf),
-}
-
 pub(crate) struct ArArchiveBuilderBuilder;
 
 impl ArchiveBuilderBuilder for ArArchiveBuilderBuilder {
     fn new_archive_builder<'a>(&self, sess: &'a Session) -> Box<dyn ArchiveBuilder<'a> + 'a> {
-        Box::new(ArArchiveBuilder {
-            sess,
-            use_gnu_style_archive: sess.target.archive_format == "gnu",
-            // FIXME fix builtin ranlib on macOS
-            no_builtin_ranlib: sess.target.is_like_osx,
-
-            src_archives: vec![],
-            entries: vec![],
-        })
+        Box::new(ArArchiveBuilder::new(sess, get_native_object_symbols))
     }
 
     fn create_dll_import_lib(
@@ -40,200 +20,6 @@ fn create_dll_import_lib(
         _tmpdir: &Path,
         _is_direct_dependency: bool,
     ) -> PathBuf {
-        bug!("creating dll imports is not supported");
-    }
-}
-
-pub(crate) struct ArArchiveBuilder<'a> {
-    sess: &'a Session,
-    use_gnu_style_archive: bool,
-    no_builtin_ranlib: bool,
-
-    src_archives: Vec<File>,
-    // Don't use `HashMap` here, as the order is important. `rust.metadata.bin` must always be at
-    // the end of an archive for linkers to not get confused.
-    entries: Vec<(Vec<u8>, ArchiveEntry)>,
-}
-
-impl<'a> ArchiveBuilder<'a> for ArArchiveBuilder<'a> {
-    fn add_file(&mut self, file: &Path) {
-        self.entries.push((
-            file.file_name().unwrap().to_str().unwrap().to_string().into_bytes(),
-            ArchiveEntry::File(file.to_owned()),
-        ));
-    }
-
-    fn add_archive(
-        &mut self,
-        archive_path: &Path,
-        mut skip: Box<dyn FnMut(&str) -> bool + 'static>,
-    ) -> std::io::Result<()> {
-        let read_cache = ReadCache::new(std::fs::File::open(&archive_path)?);
-        let archive = ArchiveFile::parse(&read_cache).unwrap();
-        let archive_index = self.src_archives.len();
-
-        for entry in archive.members() {
-            let entry = entry.map_err(|err| io::Error::new(io::ErrorKind::InvalidData, err))?;
-            let file_name = String::from_utf8(entry.name().to_vec())
-                .map_err(|err| io::Error::new(io::ErrorKind::InvalidData, err))?;
-            if !skip(&file_name) {
-                self.entries.push((
-                    file_name.into_bytes(),
-                    ArchiveEntry::FromArchive { archive_index, file_range: entry.file_range() },
-                ));
-            }
-        }
-
-        self.src_archives.push(read_cache.into_inner());
-        Ok(())
-    }
-
-    fn build(mut self: Box<Self>, output: &Path) -> bool {
-        enum BuilderKind {
-            Bsd(ar::Builder<File>),
-            Gnu(ar::GnuBuilder<File>),
-        }
-
-        let sess = self.sess;
-
-        let mut symbol_table = BTreeMap::new();
-
-        let mut entries = Vec::new();
-
-        for (mut entry_name, entry) in self.entries {
-            // FIXME only read the symbol table of the object files to avoid having to keep all
-            // object files in memory at once, or read them twice.
-            let data = match entry {
-                ArchiveEntry::FromArchive { archive_index, file_range } => {
-                    // FIXME read symbols from symtab
-                    let src_read_cache = &mut self.src_archives[archive_index];
-
-                    src_read_cache.seek(io::SeekFrom::Start(file_range.0)).unwrap();
-                    let mut data = std::vec::from_elem(0, usize::try_from(file_range.1).unwrap());
-                    src_read_cache.read_exact(&mut data).unwrap();
-
-                    data
-                }
-                ArchiveEntry::File(file) => std::fs::read(file).unwrap_or_else(|err| {
-                    sess.fatal(&format!(
-                        "error while reading object file during archive building: {}",
-                        err
-                    ));
-                }),
-            };
-
-            if !self.no_builtin_ranlib {
-                if symbol_table.contains_key(&entry_name) {
-                    // The ar crate can't handle creating a symbol table in case of multiple archive
-                    // members with the same name. Work around this by prepending a number until we
-                    // get a unique name.
-                    for i in 1.. {
-                        let new_name = format!("{}_", i)
-                            .into_bytes()
-                            .into_iter()
-                            .chain(entry_name.iter().copied())
-                            .collect::<Vec<_>>();
-                        if !symbol_table.contains_key(&new_name) {
-                            entry_name = new_name;
-                            break;
-                        }
-                    }
-                }
-
-                match object::File::parse(&*data) {
-                    Ok(object) => {
-                        symbol_table.insert(
-                            entry_name.to_vec(),
-                            object
-                                .symbols()
-                                .filter_map(|symbol| {
-                                    if symbol.is_undefined() || symbol.is_local() {
-                                        None
-                                    } else {
-                                        symbol.name().map(|name| name.as_bytes().to_vec()).ok()
-                                    }
-                                })
-                                .collect::<Vec<_>>(),
-                        );
-                    }
-                    Err(err) => {
-                        let err = err.to_string();
-                        if err == "Unknown file magic" {
-                            // Not an object file; skip it.
-                        } else if object::read::archive::ArchiveFile::parse(&*data).is_ok() {
-                            // Nested archive file; skip it.
-                        } else {
-                            sess.fatal(&format!(
-                                "error parsing `{}` during archive creation: {}",
-                                String::from_utf8_lossy(&entry_name),
-                                err
-                            ));
-                        }
-                    }
-                }
-            }
-
-            entries.push((entry_name, data));
-        }
-
-        let mut builder = if self.use_gnu_style_archive {
-            BuilderKind::Gnu(
-                ar::GnuBuilder::new(
-                    File::create(output).unwrap_or_else(|err| {
-                        sess.fatal(&format!(
-                            "error opening destination during archive building: {}",
-                            err
-                        ));
-                    }),
-                    entries.iter().map(|(name, _)| name.clone()).collect(),
-                    ar::GnuSymbolTableFormat::Size32,
-                    symbol_table,
-                )
-                .unwrap(),
-            )
-        } else {
-            BuilderKind::Bsd(
-                ar::Builder::new(
-                    File::create(output).unwrap_or_else(|err| {
-                        sess.fatal(&format!(
-                            "error opening destination during archive building: {}",
-                            err
-                        ));
-                    }),
-                    symbol_table,
-                )
-                .unwrap(),
-            )
-        };
-
-        let any_members = !entries.is_empty();
-
-        // Add all files
-        for (entry_name, data) in entries.into_iter() {
-            let header = ar::Header::new(entry_name, data.len() as u64);
-            match builder {
-                BuilderKind::Bsd(ref mut builder) => builder.append(&header, &mut &*data).unwrap(),
-                BuilderKind::Gnu(ref mut builder) => builder.append(&header, &mut &*data).unwrap(),
-            }
-        }
-
-        // Finalize archive
-        std::mem::drop(builder);
-
-        if self.no_builtin_ranlib {
-            let ranlib = crate::toolchain::get_toolchain_binary(self.sess, "ranlib");
-
-            // Run ranlib to be able to link the archive
-            let status = std::process::Command::new(ranlib)
-                .arg(output)
-                .status()
-                .expect("Couldn't run ranlib");
-
-            if !status.success() {
-                self.sess.fatal(&format!("Ranlib exited with code {:?}", status.code()));
-            }
-        }
-
-        any_members
+        unimplemented!("creating dll imports is not yet supported");
     }
 }
index 1db44502742e921b4bcbbdff9d76bce7e1e5e849..06813d7ec953f558a44eec3eb059723167e45131 100644 (file)
@@ -372,8 +372,10 @@ fn codegen_fn_body(fx: &mut FunctionCx<'_, '_, '_>, start_block: Block) {
                 }
             }
 
-            TerminatorKind::SwitchInt { discr, switch_ty, targets } => {
-                let discr = codegen_operand(fx, discr).load_scalar(fx);
+            TerminatorKind::SwitchInt { discr, targets } => {
+                let discr = codegen_operand(fx, discr);
+                let switch_ty = discr.layout().ty;
+                let discr = discr.load_scalar(fx);
 
                 let use_bool_opt = switch_ty.kind() == fx.tcx.types.bool.kind()
                     || (targets.iter().count() == 1 && targets.iter().next().unwrap().0 == 0);
index 6df2102470fe680daa1495b97cc47badc53d8619..1cb219e12e04d5a88bea03e20028a78c4eab377c 100644 (file)
@@ -11,12 +11,6 @@ dependencies = [
  "memchr",
 ]
 
-[[package]]
-name = "ar"
-version = "0.8.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "450575f58f7bee32816abbff470cbc47797397c2a81e0eaced4b98436daf52e1"
-
 [[package]]
 name = "bitflags"
 version = "1.3.2"
@@ -212,10 +206,8 @@ dependencies = [
 name = "rustc_codegen_gcc"
 version = "0.1.0"
 dependencies = [
- "ar",
  "gccjit",
  "lang_tester",
- "target-lexicon",
  "tempfile",
 ]
 
@@ -228,12 +220,6 @@ dependencies = [
  "winapi-util",
 ]
 
-[[package]]
-name = "target-lexicon"
-version = "0.10.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ab0e7238dcc7b40a7be719a25365910f6807bd864f4cce6b2e6b873658e2b19d"
-
 [[package]]
 name = "tempfile"
 version = "3.2.0"
index 211d19a8dc8909546bac8558553d2f8ca5c9959c..1f3da2f799b781991000e123eceb6d9e3547db23 100644 (file)
@@ -27,10 +27,6 @@ gccjit = { git = "https://github.com/antoyo/gccjit.rs" }
 # Local copy.
 #gccjit = { path = "../gccjit.rs" }
 
-target-lexicon = "0.10.0"
-
-ar = "0.8.0"
-
 [dev-dependencies]
 lang_tester = "0.3.9"
 tempfile = "3.1.0"
index f18ae7ea5e9b0ff75a07d9567562c9663e5a1f7c..11fa074f5ac79e81a9902d8b93c5ce9839727423 100644 (file)
@@ -1,44 +1,17 @@
-use std::fs::File;
 use std::path::{Path, PathBuf};
 
-use crate::errors::RanlibFailure;
-
-use rustc_codegen_ssa::back::archive::{ArchiveBuilder, ArchiveBuilderBuilder};
+use rustc_codegen_ssa::back::archive::{
+    get_native_object_symbols, ArArchiveBuilder, ArchiveBuilder, ArchiveBuilderBuilder,
+};
 use rustc_session::Session;
 
 use rustc_session::cstore::DllImport;
 
-struct ArchiveConfig<'a> {
-    sess: &'a Session,
-    use_native_ar: bool,
-    use_gnu_style_archive: bool,
-}
-
-#[derive(Debug)]
-enum ArchiveEntry {
-    FromArchive {
-        archive_index: usize,
-        entry_index: usize,
-    },
-    File(PathBuf),
-}
-
-pub struct ArArchiveBuilderBuilder;
+pub(crate) struct ArArchiveBuilderBuilder;
 
 impl ArchiveBuilderBuilder for ArArchiveBuilderBuilder {
     fn new_archive_builder<'a>(&self, sess: &'a Session) -> Box<dyn ArchiveBuilder<'a> + 'a> {
-        let config = ArchiveConfig {
-            sess,
-            use_native_ar: false,
-            // FIXME test for linux and System V derivatives instead
-            use_gnu_style_archive: sess.target.options.archive_format == "gnu",
-        };
-
-        Box::new(ArArchiveBuilder {
-            config,
-            src_archives: vec![],
-            entries: vec![],
-        })
+        Box::new(ArArchiveBuilder::new(sess, get_native_object_symbols))
     }
 
     fn create_dll_import_lib(
@@ -49,144 +22,6 @@ fn create_dll_import_lib(
         _tmpdir: &Path,
         _is_direct_dependency: bool,
     ) -> PathBuf {
-        unimplemented!();
-    }
-}
-
-pub struct ArArchiveBuilder<'a> {
-    config: ArchiveConfig<'a>,
-    src_archives: Vec<(PathBuf, ar::Archive<File>)>,
-    // Don't use `HashMap` here, as the order is important. `rust.metadata.bin` must always be at
-    // the end of an archive for linkers to not get confused.
-    entries: Vec<(String, ArchiveEntry)>,
-}
-
-impl<'a> ArchiveBuilder<'a> for ArArchiveBuilder<'a> {
-    fn add_file(&mut self, file: &Path) {
-        self.entries.push((
-            file.file_name().unwrap().to_str().unwrap().to_string(),
-            ArchiveEntry::File(file.to_owned()),
-        ));
-    }
-
-    fn add_archive(
-        &mut self,
-        archive_path: &Path,
-        mut skip: Box<dyn FnMut(&str) -> bool + 'static>,
-    ) -> std::io::Result<()> {
-        let mut archive = ar::Archive::new(std::fs::File::open(&archive_path)?);
-        let archive_index = self.src_archives.len();
-
-        let mut i = 0;
-        while let Some(entry) = archive.next_entry() {
-            let entry = entry?;
-            let file_name = String::from_utf8(entry.header().identifier().to_vec())
-                .map_err(|err| std::io::Error::new(std::io::ErrorKind::InvalidData, err))?;
-            if !skip(&file_name) {
-                self.entries
-                    .push((file_name, ArchiveEntry::FromArchive { archive_index, entry_index: i }));
-            }
-            i += 1;
-        }
-
-        self.src_archives.push((archive_path.to_owned(), archive));
-        Ok(())
-    }
-
-    fn build(mut self: Box<Self>, output: &Path) -> bool {
-        use std::process::Command;
-
-        fn add_file_using_ar(archive: &Path, file: &Path) {
-            Command::new("ar")
-                .arg("r") // add or replace file
-                .arg("-c") // silence created file message
-                .arg(archive)
-                .arg(&file)
-                .status()
-                .unwrap();
-        }
-
-        enum BuilderKind<'a> {
-            Bsd(ar::Builder<File>),
-            Gnu(ar::GnuBuilder<File>),
-            NativeAr(&'a Path),
-        }
-
-        let mut builder = if self.config.use_native_ar {
-            BuilderKind::NativeAr(output)
-        } else if self.config.use_gnu_style_archive {
-            BuilderKind::Gnu(ar::GnuBuilder::new(
-                File::create(output).unwrap(),
-                self.entries
-                    .iter()
-                    .map(|(name, _)| name.as_bytes().to_vec())
-                    .collect(),
-            ))
-        } else {
-            BuilderKind::Bsd(ar::Builder::new(File::create(output).unwrap()))
-        };
-
-        let any_members = !self.entries.is_empty();
-
-        // Add all files
-        for (entry_name, entry) in self.entries.into_iter() {
-            match entry {
-                ArchiveEntry::FromArchive {
-                    archive_index,
-                    entry_index,
-                } => {
-                    let (ref src_archive_path, ref mut src_archive) =
-                        self.src_archives[archive_index];
-                    let entry = src_archive.jump_to_entry(entry_index).unwrap();
-                    let header = entry.header().clone();
-
-                    match builder {
-                        BuilderKind::Bsd(ref mut builder) => {
-                            builder.append(&header, entry).unwrap()
-                        }
-                        BuilderKind::Gnu(ref mut builder) => {
-                            builder.append(&header, entry).unwrap()
-                        }
-                        BuilderKind::NativeAr(archive_file) => {
-                            Command::new("ar")
-                                .arg("x")
-                                .arg(src_archive_path)
-                                .arg(&entry_name)
-                                .status()
-                                .unwrap();
-                            add_file_using_ar(archive_file, Path::new(&entry_name));
-                            std::fs::remove_file(entry_name).unwrap();
-                        }
-                    }
-                }
-                ArchiveEntry::File(file) =>
-                    match builder {
-                        BuilderKind::Bsd(ref mut builder) => {
-                            builder
-                                .append_file(entry_name.as_bytes(), &mut File::open(file).expect("file for bsd builder"))
-                                .unwrap()
-                        },
-                        BuilderKind::Gnu(ref mut builder) => {
-                            builder
-                                .append_file(entry_name.as_bytes(), &mut File::open(&file).expect(&format!("file {:?} for gnu builder", file)))
-                                .unwrap()
-                        },
-                        BuilderKind::NativeAr(archive_file) => add_file_using_ar(archive_file, &file),
-                    },
-            }
-        }
-
-        // Finalize archive
-        std::mem::drop(builder);
-
-        // Run ranlib to be able to link the archive
-        let status =
-            std::process::Command::new("ranlib").arg(output).status().expect("Couldn't run ranlib");
-
-        if !status.success() {
-            self.config.sess.emit_fatal(RanlibFailure::new(status.code()));
-        }
-
-        any_members
+        unimplemented!("creating dll imports is not yet supported");
     }
 }
index 111bfeb1322038961f693f4d924b9ff18754d600..ea8ab76114604208ed7a9b619dc257e4e9e9c4ff 100644 (file)
@@ -8,13 +8,11 @@
 use rustc_middle::ty::{self, Instance, Ty};
 use rustc_middle::ty::layout::LayoutOf;
 use rustc_middle::mir::interpret::{self, ConstAllocation, ErrorHandled, Scalar as InterpScalar, read_target_uint};
-use rustc_span::Span;
 use rustc_span::def_id::DefId;
 use rustc_target::abi::{self, Align, HasDataLayout, Primitive, Size, WrappingRange};
 
 use crate::base;
 use crate::context::CodegenCx;
-use crate::errors::LinkageConstOrMutType;
 use crate::type_of::LayoutGccExt;
 
 impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
@@ -239,12 +237,12 @@ pub fn get_static(&self, def_id: DefId) -> LValue<'gcc> {
                     }
 
                     Node::ForeignItem(&hir::ForeignItem {
-                        span,
+                        span: _,
                         kind: hir::ForeignItemKind::Static(..),
                         ..
                     }) => {
                         let fn_attrs = self.tcx.codegen_fn_attrs(def_id);
-                        check_and_apply_linkage(&self, &fn_attrs, ty, sym, span)
+                        check_and_apply_linkage(&self, &fn_attrs, ty, sym)
                     }
 
                     item => bug!("get_static: expected static, found {:?}", item),
@@ -257,8 +255,7 @@ pub fn get_static(&self, def_id: DefId) -> LValue<'gcc> {
                 //debug!("get_static: sym={} item_attr={:?}", sym, self.tcx.item_attrs(def_id));
 
                 let attrs = self.tcx.codegen_fn_attrs(def_id);
-                let span = self.tcx.def_span(def_id);
-                let global = check_and_apply_linkage(&self, &attrs, ty, sym, span);
+                let global = check_and_apply_linkage(&self, &attrs, ty, sym);
 
                 let needs_dll_storage_attr = false; // TODO(antoyo)
 
@@ -355,24 +352,12 @@ pub fn codegen_static_initializer<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, def_id
     Ok((const_alloc_to_gcc(cx, alloc), alloc))
 }
 
-fn check_and_apply_linkage<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, attrs: &CodegenFnAttrs, ty: Ty<'tcx>, sym: &str, span: Span) -> LValue<'gcc> {
+fn check_and_apply_linkage<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, attrs: &CodegenFnAttrs, ty: Ty<'tcx>, sym: &str) -> LValue<'gcc> {
     let is_tls = attrs.flags.contains(CodegenFnAttrFlags::THREAD_LOCAL);
     let llty = cx.layout_of(ty).gcc_type(cx, true);
-    if let Some(linkage) = attrs.linkage {
-        // If this is a static with a linkage specified, then we need to handle
-        // it a little specially. The typesystem prevents things like &T and
-        // extern "C" fn() from being non-null, so we can't just declare a
-        // static and call it a day. Some linkages (like weak) will make it such
-        // that the static actually has a null value.
-        let llty2 =
-            if let ty::RawPtr(ref mt) = ty.kind() {
-                cx.layout_of(mt.ty).gcc_type(cx, true)
-            }
-            else {
-                cx.sess().emit_fatal(LinkageConstOrMutType { span: span })
-            };
+    if let Some(linkage) = attrs.import_linkage {
         // Declare a symbol `foo` with the desired linkage.
-        let global1 = cx.declare_global_with_linkage(&sym, llty2, base::global_linkage_to_gcc(linkage));
+        let global1 = cx.declare_global_with_linkage(&sym, cx.type_i8(), base::global_linkage_to_gcc(linkage));
 
         // Declare an internal global `extern_with_linkage_foo` which
         // is initialized with the address of `foo`.  If `foo` is
index 15ad90f9043c0643f3fd34053c4210394c5f8b5a..d0ba7e2479111fed3ee8661f86984a3fbfd18cf2 100644 (file)
@@ -16,18 +16,6 @@ fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
     }
 }
 
-#[derive(Diagnostic)]
-#[diag(codegen_gcc_ranlib_failure)]
-pub(crate) struct RanlibFailure {
-    exit_code: ExitCode,
-}
-
-impl RanlibFailure {
-    pub fn new(exit_code: Option<i32>) -> Self {
-        RanlibFailure { exit_code: ExitCode(exit_code) }
-    }
-}
-
 #[derive(Diagnostic)]
 #[diag(codegen_gcc_invalid_monomorphization_basic_integer, code = "E0511")]
 pub(crate) struct InvalidMonomorphizationBasicInteger<'a> {
@@ -223,13 +211,6 @@ pub(crate) struct InvalidMonomorphizationUnsupportedOperation<'a> {
     pub in_elem: Ty<'a>,
 }
 
-#[derive(Diagnostic)]
-#[diag(codegen_gcc_linkage_const_or_mut_type)]
-pub(crate) struct LinkageConstOrMutType {
-    #[primary_span]
-    pub span: Span
-}
-
 #[derive(Diagnostic)]
 #[diag(codegen_gcc_lto_not_supported)]
 pub(crate) struct LTONotSupported;
@@ -238,5 +219,5 @@ pub(crate) struct LinkageConstOrMutType {
 #[diag(codegen_gcc_unwinding_inline_asm)]
 pub(crate) struct UnwindingInlineAsm {
     #[primary_span]
-    pub span: Span
+    pub span: Span,
 }
index bdf7318ce48c9505887b2287c0201bf66742bc54..89a415cdb36cd2d8d98c0b1f132541e018364f39 100644 (file)
@@ -300,4 +300,8 @@ fn typeid_metadata(&self, _typeid: String) -> RValue<'gcc> {
         // Unsupported.
         self.context.new_rvalue_from_int(self.int_type, 0)
     }
+
+    fn set_kcfi_type_metadata(&self, _function: RValue<'gcc>, _kcfi_typeid: u32) {
+        // Unsupported.
+    }
 }
index 0ad39c24025fd6ba8e8b19642f45b0836bf2386c..93d6234dc884550875cf4aef0b3ce89dc2250f5d 100644 (file)
@@ -11,7 +11,7 @@ bitflags = "1.0"
 cstr = "0.2"
 libc = "0.2"
 measureme = "10.0.0"
-object = { version = "0.29.0", default-features = false, features = ["std", "read_core", "archive", "coff", "elf", "macho", "pe"] }
+object = { version = "0.29.0", default-features = false, features = ["std", "read"] }
 tracing = "0.1"
 rustc_middle = { path = "../rustc_middle" }
 rustc-demangle = "0.1.21"
index fed56cdd43821e6cb2dd76a0918e7dcc5c55bf32..668d929270530023e08c94352b9d7522b3871e75 100644 (file)
@@ -88,7 +88,8 @@ pub(crate) unsafe fn codegen(
             callee,
             args.as_ptr(),
             args.len() as c_uint,
-            None,
+            [].as_ptr(),
+            0 as c_uint,
         );
         llvm::LLVMSetTailCall(ret, True);
         if output.is_some() {
@@ -132,8 +133,15 @@ pub(crate) unsafe fn codegen(
         .enumerate()
         .map(|(i, _)| llvm::LLVMGetParam(llfn, i as c_uint))
         .collect::<Vec<_>>();
-    let ret =
-        llvm::LLVMRustBuildCall(llbuilder, ty, callee, args.as_ptr(), args.len() as c_uint, None);
+    let ret = llvm::LLVMRustBuildCall(
+        llbuilder,
+        ty,
+        callee,
+        args.as_ptr(),
+        args.len() as c_uint,
+        [].as_ptr(),
+        0 as c_uint,
+    );
     llvm::LLVMSetTailCall(ret, True);
     llvm::LLVMBuildRetVoid(llbuilder);
     llvm::LLVMDisposeBuilder(llbuilder);
index a8b47633519aabc39689ab19a7138c269b11440c..f3bdacf6085552109871140a10cacd1e2757d24b 100644 (file)
@@ -258,13 +258,12 @@ pub fn from_fn_attrs<'ll, 'tcx>(
         OptimizeAttr::Speed => {}
     }
 
-    let inline = if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::NAKED) {
-        InlineAttr::Never
-    } else if codegen_fn_attrs.inline == InlineAttr::None && instance.def.requires_inline(cx.tcx) {
-        InlineAttr::Hint
-    } else {
-        codegen_fn_attrs.inline
-    };
+    let inline =
+        if codegen_fn_attrs.inline == InlineAttr::None && instance.def.requires_inline(cx.tcx) {
+            InlineAttr::Hint
+        } else {
+            codegen_fn_attrs.inline
+        };
     to_add.extend(inline_attr(cx, inline));
 
     // The `uwtable` attribute according to LLVM is:
index 5c68abeb08baf288532e48c162926b39f92fce26..0aee1a1439b9bcd2867bb2da9681092891c257d5 100644 (file)
@@ -1,31 +1,30 @@
 //! A helper class for dealing with static archives
 
 use std::env;
-use std::ffi::{CStr, CString, OsString};
-use std::fs;
-use std::io::{self, Write};
+use std::ffi::{c_char, c_void, CStr, CString, OsString};
+use std::io;
 use std::mem;
 use std::path::{Path, PathBuf};
 use std::ptr;
 use std::str;
 
-use object::read::macho::FatArch;
-
 use crate::common;
 use crate::errors::{
-    ArchiveBuildFailure, DlltoolFailImportLibrary, ErrorCallingDllTool, ErrorCreatingImportLibrary,
-    ErrorWritingDEFFile, UnknownArchiveKind,
+    DlltoolFailImportLibrary, ErrorCallingDllTool, ErrorCreatingImportLibrary, ErrorWritingDEFFile,
 };
 use crate::llvm::archive_ro::{ArchiveRO, Child};
 use crate::llvm::{self, ArchiveKind, LLVMMachineType, LLVMRustCOFFShortExport};
-use rustc_codegen_ssa::back::archive::{ArchiveBuilder, ArchiveBuilderBuilder};
-use rustc_data_structures::memmap::Mmap;
+use rustc_codegen_ssa::back::archive::{
+    get_native_object_symbols, try_extract_macho_fat_archive, ArArchiveBuilder,
+    ArchiveBuildFailure, ArchiveBuilder, ArchiveBuilderBuilder, UnknownArchiveKind,
+};
+
 use rustc_session::cstore::DllImport;
 use rustc_session::Session;
 
 /// Helper for adding many files to an archive.
 #[must_use = "must call build() to finish building the archive"]
-pub struct LlvmArchiveBuilder<'a> {
+pub(crate) struct LlvmArchiveBuilder<'a> {
     sess: &'a Session,
     additions: Vec<Addition>,
 }
@@ -61,57 +60,6 @@ fn llvm_machine_type(cpu: &str) -> LLVMMachineType {
     }
 }
 
-fn try_filter_fat_archs(
-    archs: object::read::Result<&[impl FatArch]>,
-    target_arch: object::Architecture,
-    archive_path: &Path,
-    archive_map_data: &[u8],
-) -> io::Result<Option<PathBuf>> {
-    let archs = archs.map_err(|e| io::Error::new(io::ErrorKind::Other, e))?;
-
-    let desired = match archs.iter().filter(|a| a.architecture() == target_arch).next() {
-        Some(a) => a,
-        None => return Ok(None),
-    };
-
-    let (mut new_f, extracted_path) = tempfile::Builder::new()
-        .suffix(archive_path.file_name().unwrap())
-        .tempfile()?
-        .keep()
-        .unwrap();
-
-    new_f.write_all(
-        desired.data(archive_map_data).map_err(|e| io::Error::new(io::ErrorKind::Other, e))?,
-    )?;
-
-    Ok(Some(extracted_path))
-}
-
-fn try_extract_macho_fat_archive(
-    sess: &Session,
-    archive_path: &Path,
-) -> io::Result<Option<PathBuf>> {
-    let archive_map = unsafe { Mmap::map(fs::File::open(&archive_path)?)? };
-    let target_arch = match sess.target.arch.as_ref() {
-        "aarch64" => object::Architecture::Aarch64,
-        "x86_64" => object::Architecture::X86_64,
-        _ => return Ok(None),
-    };
-
-    match object::macho::FatHeader::parse(&*archive_map) {
-        Ok(h) if h.magic.get(object::endian::BigEndian) == object::macho::FAT_MAGIC => {
-            let archs = object::macho::FatHeader::parse_arch32(&*archive_map);
-            try_filter_fat_archs(archs, target_arch, archive_path, &*archive_map)
-        }
-        Ok(h) if h.magic.get(object::endian::BigEndian) == object::macho::FAT_MAGIC_64 => {
-            let archs = object::macho::FatHeader::parse_arch64(&*archive_map);
-            try_filter_fat_archs(archs, target_arch, archive_path, &*archive_map)
-        }
-        // Not a FatHeader at all, just return None.
-        _ => Ok(None),
-    }
-}
-
 impl<'a> ArchiveBuilder<'a> for LlvmArchiveBuilder<'a> {
     fn add_archive(
         &mut self,
@@ -160,7 +108,11 @@ fn build(mut self: Box<Self>, output: &Path) -> bool {
 
 impl ArchiveBuilderBuilder for LlvmArchiveBuilderBuilder {
     fn new_archive_builder<'a>(&self, sess: &'a Session) -> Box<dyn ArchiveBuilder<'a> + 'a> {
-        Box::new(LlvmArchiveBuilder { sess, additions: Vec::new() })
+        if sess.target.arch == "wasm32" || sess.target.arch == "wasm64" {
+            Box::new(LlvmArchiveBuilder { sess, additions: Vec::new() })
+        } else {
+            Box::new(ArArchiveBuilder::new(sess, get_llvm_object_symbols))
+        }
     }
 
     fn create_dll_import_lib(
@@ -309,6 +261,61 @@ fn create_dll_import_lib(
     }
 }
 
+// The object crate doesn't know how to get symbols for LLVM bitcode and COFF bigobj files.
+// As such we need to use LLVM for them.
+#[deny(unsafe_op_in_unsafe_fn)]
+fn get_llvm_object_symbols(
+    buf: &[u8],
+    f: &mut dyn FnMut(&[u8]) -> io::Result<()>,
+) -> io::Result<bool> {
+    let is_bitcode = unsafe { llvm::LLVMRustIsBitcode(buf.as_ptr(), buf.len()) };
+
+    // COFF bigobj file, msvc LTO file or import library. See
+    // https://github.com/llvm/llvm-project/blob/453f27bc9/llvm/lib/BinaryFormat/Magic.cpp#L38-L51
+    let is_unsupported_windows_obj_file = buf.get(0..4) == Some(b"\0\0\xFF\xFF");
+
+    if is_bitcode || is_unsupported_windows_obj_file {
+        let mut state = Box::new(f);
+
+        let err = unsafe {
+            llvm::LLVMRustGetSymbols(
+                buf.as_ptr(),
+                buf.len(),
+                &mut *state as *mut &mut _ as *mut c_void,
+                callback,
+                error_callback,
+            )
+        };
+
+        if err.is_null() {
+            return Ok(true);
+        } else {
+            return Err(unsafe { *Box::from_raw(err as *mut io::Error) });
+        }
+
+        unsafe extern "C" fn callback(
+            state: *mut c_void,
+            symbol_name: *const c_char,
+        ) -> *mut c_void {
+            let f = unsafe { &mut *(state as *mut &mut dyn FnMut(&[u8]) -> io::Result<()>) };
+            match f(unsafe { CStr::from_ptr(symbol_name) }.to_bytes()) {
+                Ok(()) => std::ptr::null_mut(),
+                Err(err) => Box::into_raw(Box::new(err)) as *mut c_void,
+            }
+        }
+
+        unsafe extern "C" fn error_callback(error: *const c_char) -> *mut c_void {
+            let error = unsafe { CStr::from_ptr(error) };
+            Box::into_raw(Box::new(io::Error::new(
+                io::ErrorKind::Other,
+                format!("LLVM error: {}", error.to_string_lossy()),
+            ))) as *mut c_void
+        }
+    } else {
+        get_native_object_symbols(buf, f)
+    }
+}
+
 impl<'a> LlvmArchiveBuilder<'a> {
     fn build_with_llvm(&mut self, output: &Path) -> io::Result<bool> {
         let kind = &*self.sess.target.archive_format;
index 3fa21355b7f4c9b46349591904aac80717541976..551663bfbbd30177707d0d72a6e901e7af4da328 100644 (file)
@@ -133,6 +133,10 @@ fn prepare_lto(
         }
     }
 
+    // __llvm_profile_counter_bias is pulled in at link time by an undefined reference to
+    // __llvm_profile_runtime, therefore we won't know until link time if this symbol
+    // should have default visibility.
+    symbols_below_threshold.push(CString::new("__llvm_profile_counter_bias").unwrap());
     Ok((symbols_below_threshold, upstream_modules))
 }
 
index 77dd15ef4d8078e8c37162776318f6068b272687..83bffb20e0ce02c706f191199119627fefe1a4f5 100644 (file)
@@ -20,6 +20,7 @@
 };
 use rustc_middle::ty::{self, Ty, TyCtxt};
 use rustc_span::Span;
+use rustc_symbol_mangling::typeid::kcfi_typeid_for_fnabi;
 use rustc_target::abi::{self, call::FnAbi, Align, Size, WrappingRange};
 use rustc_target::spec::{HasTargetSpec, Target};
 use std::borrow::Cow;
@@ -225,9 +226,25 @@ fn invoke(
         debug!("invoke {:?} with args ({:?})", llfn, args);
 
         let args = self.check_call("invoke", llty, llfn, args);
-        let bundle = funclet.map(|funclet| funclet.bundle());
-        let bundle = bundle.as_ref().map(|b| &*b.raw);
+        let funclet_bundle = funclet.map(|funclet| funclet.bundle());
+        let funclet_bundle = funclet_bundle.as_ref().map(|b| &*b.raw);
+        let mut bundles = vec![funclet_bundle];
+
+        // Set KCFI operand bundle
+        let is_indirect_call = unsafe { llvm::LLVMIsAFunction(llfn).is_none() };
+        let kcfi_bundle =
+            if self.tcx.sess.is_sanitizer_kcfi_enabled() && fn_abi.is_some() && is_indirect_call {
+                let kcfi_typeid = kcfi_typeid_for_fnabi(self.tcx, fn_abi.unwrap());
+                Some(llvm::OperandBundleDef::new("kcfi", &[self.const_u32(kcfi_typeid)]))
+            } else {
+                None
+            };
+        if kcfi_bundle.is_some() {
+            let kcfi_bundle = kcfi_bundle.as_ref().map(|b| &*b.raw);
+            bundles.push(kcfi_bundle);
+        }
 
+        bundles.retain(|bundle| bundle.is_some());
         let invoke = unsafe {
             llvm::LLVMRustBuildInvoke(
                 self.llbuilder,
@@ -237,7 +254,8 @@ fn invoke(
                 args.len() as c_uint,
                 then,
                 catch,
-                bundle,
+                bundles.as_ptr(),
+                bundles.len() as c_uint,
                 UNNAMED,
             )
         };
@@ -1143,7 +1161,8 @@ fn instrprof_increment(
                 llfn,
                 args.as_ptr() as *const &llvm::Value,
                 args.len() as c_uint,
-                None,
+                [].as_ptr(),
+                0 as c_uint,
             );
         }
     }
@@ -1159,9 +1178,25 @@ fn call(
         debug!("call {:?} with args ({:?})", llfn, args);
 
         let args = self.check_call("call", llty, llfn, args);
-        let bundle = funclet.map(|funclet| funclet.bundle());
-        let bundle = bundle.as_ref().map(|b| &*b.raw);
+        let funclet_bundle = funclet.map(|funclet| funclet.bundle());
+        let funclet_bundle = funclet_bundle.as_ref().map(|b| &*b.raw);
+        let mut bundles = vec![funclet_bundle];
+
+        // Set KCFI operand bundle
+        let is_indirect_call = unsafe { llvm::LLVMIsAFunction(llfn).is_none() };
+        let kcfi_bundle =
+            if self.tcx.sess.is_sanitizer_kcfi_enabled() && fn_abi.is_some() && is_indirect_call {
+                let kcfi_typeid = kcfi_typeid_for_fnabi(self.tcx, fn_abi.unwrap());
+                Some(llvm::OperandBundleDef::new("kcfi", &[self.const_u32(kcfi_typeid)]))
+            } else {
+                None
+            };
+        if kcfi_bundle.is_some() {
+            let kcfi_bundle = kcfi_bundle.as_ref().map(|b| &*b.raw);
+            bundles.push(kcfi_bundle);
+        }
 
+        bundles.retain(|bundle| bundle.is_some());
         let call = unsafe {
             llvm::LLVMRustBuildCall(
                 self.llbuilder,
@@ -1169,7 +1204,8 @@ fn call(
                 llfn,
                 args.as_ptr() as *const &llvm::Value,
                 args.len() as c_uint,
-                bundle,
+                bundles.as_ptr(),
+                bundles.len() as c_uint,
             )
         };
         if let Some(fn_abi) = fn_abi {
index 3c324359565c1081699b70ea2e432b23322ced98..3626aa901c0ef45b02dfa23fe54487d491436f11 100644 (file)
@@ -1,7 +1,7 @@
 use crate::base;
 use crate::common::{self, CodegenCx};
 use crate::debuginfo;
-use crate::errors::{InvalidMinimumAlignment, LinkageConstOrMutType, SymbolAlreadyDefined};
+use crate::errors::{InvalidMinimumAlignment, SymbolAlreadyDefined};
 use crate::llvm::{self, True};
 use crate::llvm_util;
 use crate::type_::Type;
@@ -162,22 +162,12 @@ fn check_and_apply_linkage<'ll, 'tcx>(
     def_id: DefId,
 ) -> &'ll Value {
     let llty = cx.layout_of(ty).llvm_type(cx);
-    if let Some(linkage) = attrs.linkage {
+    if let Some(linkage) = attrs.import_linkage {
         debug!("get_static: sym={} linkage={:?}", sym, linkage);
 
-        // If this is a static with a linkage specified, then we need to handle
-        // it a little specially. The typesystem prevents things like &T and
-        // extern "C" fn() from being non-null, so we can't just declare a
-        // static and call it a day. Some linkages (like weak) will make it such
-        // that the static actually has a null value.
-        let llty2 = if let ty::RawPtr(ref mt) = ty.kind() {
-            cx.layout_of(mt.ty).llvm_type(cx)
-        } else {
-            cx.sess().emit_fatal(LinkageConstOrMutType { span: cx.tcx.def_span(def_id) })
-        };
         unsafe {
             // Declare a symbol `foo` with the desired linkage.
-            let g1 = cx.declare_global(sym, llty2);
+            let g1 = cx.declare_global(sym, cx.type_i8());
             llvm::LLVMRustSetLinkage(g1, base::linkage_to_llvm(linkage));
 
             // Declare an internal global `extern_with_linkage_foo` which
@@ -195,7 +185,7 @@ fn check_and_apply_linkage<'ll, 'tcx>(
                 })
             });
             llvm::LLVMRustSetLinkage(g2, llvm::Linkage::InternalLinkage);
-            llvm::LLVMSetInitializer(g2, g1);
+            llvm::LLVMSetInitializer(g2, cx.const_ptrcast(g1, llty));
             g2
         }
     } else if cx.tcx.sess.target.arch == "x86" &&
index 4dcc7cd54477def2a32ab3ea7e06b9f566b08b0c..aa1735f38acfd1e8c4c65e49f1998939407e84af 100644 (file)
@@ -250,6 +250,11 @@ pub unsafe fn create_module<'ll>(
         );
     }
 
+    if sess.is_sanitizer_kcfi_enabled() {
+        let kcfi = "kcfi\0".as_ptr().cast();
+        llvm::LLVMRustAddModuleFlag(llmod, llvm::LLVMModFlagBehavior::Override, kcfi, 1);
+    }
+
     // Control Flow Guard is currently only supported by the MSVC linker on Windows.
     if sess.target.is_like_msvc {
         match sess.opts.cg.control_flow_guard {
index d87117dffdc60b41c33f6fc778a11ae719561864..a9e3dcf4cb39a7c56663f6bb271c82e0003ea71f 100644 (file)
@@ -27,9 +27,7 @@
 use rustc_fs_util::path_to_c_string;
 use rustc_hir::def::CtorKind;
 use rustc_hir::def_id::{DefId, LOCAL_CRATE};
-use rustc_index::vec::{Idx, IndexVec};
 use rustc_middle::bug;
-use rustc_middle::mir::{self, GeneratorLayout};
 use rustc_middle::ty::layout::{LayoutOf, TyAndLayout};
 use rustc_middle::ty::subst::GenericArgKind;
 use rustc_middle::ty::{
@@ -1026,33 +1024,6 @@ fn build_struct_type_di_node<'ll, 'tcx>(
 // Tuples
 //=-----------------------------------------------------------------------------
 
-/// Returns names of captured upvars for closures and generators.
-///
-/// Here are some examples:
-///  - `name__field1__field2` when the upvar is captured by value.
-///  - `_ref__name__field` when the upvar is captured by reference.
-///
-/// For generators this only contains upvars that are shared by all states.
-fn closure_saved_names_of_captured_variables(tcx: TyCtxt<'_>, def_id: DefId) -> SmallVec<String> {
-    let body = tcx.optimized_mir(def_id);
-
-    body.var_debug_info
-        .iter()
-        .filter_map(|var| {
-            let is_ref = match var.value {
-                mir::VarDebugInfoContents::Place(place) if place.local == mir::Local::new(1) => {
-                    // The projection is either `[.., Field, Deref]` or `[.., Field]`. It
-                    // implies whether the variable is captured by value or by reference.
-                    matches!(place.projection.last().unwrap(), mir::ProjectionElem::Deref)
-                }
-                _ => return None,
-            };
-            let prefix = if is_ref { "_ref__" } else { "" };
-            Some(prefix.to_owned() + var.name.as_str())
-        })
-        .collect()
-}
-
 /// Builds the DW_TAG_member debuginfo nodes for the upvars of a closure or generator.
 /// For a generator, this will handle upvars shared by all states.
 fn build_upvar_field_di_nodes<'ll, 'tcx>(
@@ -1083,7 +1054,7 @@ fn build_upvar_field_di_nodes<'ll, 'tcx>(
             .all(|&t| t == cx.tcx.normalize_erasing_regions(ParamEnv::reveal_all(), t))
     );
 
-    let capture_names = closure_saved_names_of_captured_variables(cx.tcx, def_id);
+    let capture_names = cx.tcx.closure_saved_names_of_captured_variables(def_id);
     let layout = cx.layout_of(closure_or_generator_ty);
 
     up_var_tys
@@ -1229,43 +1200,6 @@ fn build_union_type_di_node<'ll, 'tcx>(
     )
 }
 
-// FIXME(eddyb) maybe precompute this? Right now it's computed once
-// per generator monomorphization, but it doesn't depend on substs.
-fn generator_layout_and_saved_local_names<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    def_id: DefId,
-) -> (&'tcx GeneratorLayout<'tcx>, IndexVec<mir::GeneratorSavedLocal, Option<Symbol>>) {
-    let body = tcx.optimized_mir(def_id);
-    let generator_layout = body.generator_layout().unwrap();
-    let mut generator_saved_local_names = IndexVec::from_elem(None, &generator_layout.field_tys);
-
-    let state_arg = mir::Local::new(1);
-    for var in &body.var_debug_info {
-        let mir::VarDebugInfoContents::Place(place) = &var.value else { continue };
-        if place.local != state_arg {
-            continue;
-        }
-        match place.projection[..] {
-            [
-                // Deref of the `Pin<&mut Self>` state argument.
-                mir::ProjectionElem::Field(..),
-                mir::ProjectionElem::Deref,
-                // Field of a variant of the state.
-                mir::ProjectionElem::Downcast(_, variant),
-                mir::ProjectionElem::Field(field, _),
-            ] => {
-                let name = &mut generator_saved_local_names
-                    [generator_layout.variant_fields[variant][field]];
-                if name.is_none() {
-                    name.replace(var.name);
-                }
-            }
-            _ => {}
-        }
-    }
-    (generator_layout, generator_saved_local_names)
-}
-
 /// Computes the type parameters for a type, if any, for the given metadata.
 fn build_generic_type_param_di_nodes<'ll, 'tcx>(
     cx: &CodegenCx<'ll, 'tcx>,
index 53e8a291d1e8aa4d9a4cd90530b27ed0ad04edfa..69443b9b828e2caf3a19ba382557c3431ada8169 100644 (file)
@@ -22,9 +22,9 @@
     common::CodegenCx,
     debuginfo::{
         metadata::{
-            build_field_di_node, closure_saved_names_of_captured_variables,
+            build_field_di_node,
             enums::{tag_base_type, DiscrResult},
-            file_metadata, generator_layout_and_saved_local_names, size_and_align_of, type_di_node,
+            file_metadata, size_and_align_of, type_di_node,
             type_map::{self, Stub, UniqueTypeId},
             unknown_file_metadata, DINodeCreationResult, SmallVec, NO_GENERICS, NO_SCOPE_METADATA,
             UNKNOWN_LINE_NUMBER,
@@ -677,9 +677,9 @@ fn build_union_fields_for_direct_tag_generator<'ll, 'tcx>(
     };
 
     let (generator_layout, state_specific_upvar_names) =
-        generator_layout_and_saved_local_names(cx.tcx, generator_def_id);
+        cx.tcx.generator_layout_and_saved_local_names(generator_def_id);
 
-    let common_upvar_names = closure_saved_names_of_captured_variables(cx.tcx, generator_def_id);
+    let common_upvar_names = cx.tcx.closure_saved_names_of_captured_variables(generator_def_id);
     let variant_range = generator_substs.variant_range(generator_def_id, cx.tcx);
     let variant_count = (variant_range.start.as_u32()..variant_range.end.as_u32()).len();
 
index becbccc434d9ac33ee30091225aa0b87278986b7..93419d27a6236c5356a1a4045c7e05b0225794a6 100644 (file)
@@ -4,9 +4,8 @@
     common::CodegenCx,
     debuginfo::{
         metadata::{
-            closure_saved_names_of_captured_variables,
             enums::tag_base_type,
-            file_metadata, generator_layout_and_saved_local_names, size_and_align_of, type_di_node,
+            file_metadata, size_and_align_of, type_di_node,
             type_map::{self, Stub, StubInfo, UniqueTypeId},
             unknown_file_metadata, DINodeCreationResult, SmallVec, NO_GENERICS,
             UNKNOWN_LINE_NUMBER,
@@ -157,7 +156,7 @@ pub(super) fn build_generator_di_node<'ll, 'tcx>(
         ),
         |cx, generator_type_di_node| {
             let (generator_layout, state_specific_upvar_names) =
-                generator_layout_and_saved_local_names(cx.tcx, generator_def_id);
+                cx.tcx.generator_layout_and_saved_local_names(generator_def_id);
 
             let Variants::Multiple { tag_encoding: TagEncoding::Direct, ref variants, .. } = generator_type_and_layout.variants else {
                 bug!(
@@ -167,7 +166,7 @@ pub(super) fn build_generator_di_node<'ll, 'tcx>(
             };
 
             let common_upvar_names =
-                closure_saved_names_of_captured_variables(cx.tcx, generator_def_id);
+                cx.tcx.closure_saved_names_of_captured_variables(generator_def_id);
 
             // Build variant struct types
             let variant_struct_type_di_nodes: SmallVec<_> = variants
index dc21a02cec44a144fef0c9704b3a16af5c1868d2..6a575095f7e45dbc5e05a7b86cebd7ce2851925e 100644 (file)
@@ -20,7 +20,7 @@
 use crate::value::Value;
 use rustc_codegen_ssa::traits::TypeMembershipMethods;
 use rustc_middle::ty::Ty;
-use rustc_symbol_mangling::typeid::typeid_for_fnabi;
+use rustc_symbol_mangling::typeid::{kcfi_typeid_for_fnabi, typeid_for_fnabi};
 use smallvec::SmallVec;
 
 /// Declare a function.
@@ -136,6 +136,11 @@ pub fn declare_fn(&self, name: &str, fn_abi: &FnAbi<'tcx, Ty<'tcx>>) -> &'ll Val
             self.set_type_metadata(llfn, typeid);
         }
 
+        if self.tcx.sess.is_sanitizer_kcfi_enabled() {
+            let kcfi_typeid = kcfi_typeid_for_fnabi(self.tcx, fn_abi);
+            self.set_kcfi_type_metadata(llfn, kcfi_typeid);
+        }
+
         llfn
     }
 
index 0fafc214f2f5ebdc6144ff8dbd8f154d3a3b2814..af9f31fc3249309ee4aee8db7d4b0176f5fabf75 100644 (file)
@@ -61,23 +61,10 @@ pub(crate) struct InvalidMinimumAlignment {
     pub err: String,
 }
 
-#[derive(Diagnostic)]
-#[diag(codegen_llvm_linkage_const_or_mut_type)]
-pub(crate) struct LinkageConstOrMutType {
-    #[primary_span]
-    pub span: Span,
-}
-
 #[derive(Diagnostic)]
 #[diag(codegen_llvm_sanitizer_memtag_requires_mte)]
 pub(crate) struct SanitizerMemtagRequiresMte;
 
-#[derive(Diagnostic)]
-#[diag(codegen_llvm_archive_build_failure)]
-pub(crate) struct ArchiveBuildFailure {
-    pub error: std::io::Error,
-}
-
 #[derive(Diagnostic)]
 #[diag(codegen_llvm_error_writing_def_file)]
 pub(crate) struct ErrorWritingDEFFile {
@@ -97,12 +84,6 @@ pub(crate) struct DlltoolFailImportLibrary<'a> {
     pub stderr: Cow<'a, str>,
 }
 
-#[derive(Diagnostic)]
-#[diag(codegen_llvm_unknown_archive_kind)]
-pub(crate) struct UnknownArchiveKind<'a> {
-    pub kind: &'a str,
-}
-
 #[derive(Diagnostic)]
 #[diag(codegen_llvm_dynamic_linking_with_lto)]
 #[note]
index c14e1656291e87710f422f5abee59bb1eb13a072..e61dbe8b8fc50dfbd2c0fe6de8fc8c7604b06974 100644 (file)
@@ -427,6 +427,7 @@ pub enum MetadataType {
     MD_type = 19,
     MD_vcall_visibility = 28,
     MD_noundef = 29,
+    MD_kcfi_type = 36,
 }
 
 /// LLVMRustAsmDialect
@@ -983,6 +984,9 @@ pub struct AllocKindFlags : u64 {
     unsafe extern "C" fn(*mut c_void, *const c_char, *const c_char);
 pub type SelfProfileAfterPassCallback = unsafe extern "C" fn(*mut c_void);
 
+pub type GetSymbolsCallback = unsafe extern "C" fn(*mut c_void, *const c_char) -> *mut c_void;
+pub type GetSymbolsErrorCallback = unsafe extern "C" fn(*const c_char) -> *mut c_void;
+
 extern "C" {
     pub fn LLVMRustInstallFatalErrorHandler();
     pub fn LLVMRustDisableSystemDialogsOnCrash();
@@ -1060,6 +1064,7 @@ pub fn LLVMStructTypeInContext<'a>(
     pub fn LLVMGlobalSetMetadata<'a>(Val: &'a Value, KindID: c_uint, Metadata: &'a Metadata);
     pub fn LLVMRustGlobalAddMetadata<'a>(Val: &'a Value, KindID: c_uint, Metadata: &'a Metadata);
     pub fn LLVMValueAsMetadata(Node: &Value) -> &Metadata;
+    pub fn LLVMIsAFunction(Val: &Value) -> Option<&Value>;
 
     // Operations on constants of any type
     pub fn LLVMConstNull(Ty: &Type) -> &Value;
@@ -1270,7 +1275,8 @@ pub fn LLVMRustBuildInvoke<'a>(
         NumArgs: c_uint,
         Then: &'a BasicBlock,
         Catch: &'a BasicBlock,
-        Bundle: Option<&OperandBundleDef<'a>>,
+        OpBundles: *const Option<&OperandBundleDef<'a>>,
+        NumOpBundles: c_uint,
         Name: *const c_char,
     ) -> &'a Value;
     pub fn LLVMBuildLandingPad<'a>(
@@ -1640,7 +1646,8 @@ pub fn LLVMRustBuildCall<'a>(
         Fn: &'a Value,
         Args: *const &'a Value,
         NumArgs: c_uint,
-        Bundle: Option<&OperandBundleDef<'a>>,
+        OpBundles: *const Option<&OperandBundleDef<'a>>,
+        NumOpBundles: c_uint,
     ) -> &'a Value;
     pub fn LLVMRustBuildMemCpy<'a>(
         B: &Builder<'a>,
@@ -2474,4 +2481,14 @@ pub fn LLVMRustContextConfigureDiagnosticHandler(
     pub fn LLVMRustGetMangledName(V: &Value, out: &RustString);
 
     pub fn LLVMRustGetElementTypeArgIndex(CallSite: &Value) -> i32;
+
+    pub fn LLVMRustIsBitcode(ptr: *const u8, len: usize) -> bool;
+
+    pub fn LLVMRustGetSymbols(
+        buf_ptr: *const u8,
+        buf_len: usize,
+        state: *mut c_void,
+        callback: GetSymbolsCallback,
+        error_callback: GetSymbolsErrorCallback,
+    ) -> *mut c_void;
 }
index c9f5dd0f2c68b86e3b13d4ac911fe8f1cf5edf44..2fa602520dcb0d72e02132a481f86fe6b0ec8f82 100644 (file)
@@ -494,6 +494,11 @@ pub(crate) fn global_llvm_features(sess: &Session, diagnostics: bool) -> Vec<Str
         .flatten();
     features.extend(feats);
 
+    // FIXME: Move v8a to target definition list when earliest supported LLVM is 14.
+    if get_version() >= (14, 0, 0) && sess.target.arch == "aarch64" {
+        features.push("+v8a".into());
+    }
+
     if diagnostics && let Some(f) = check_tied_features(sess, &featsmap) {
         sess.emit_err(TargetFeatureDisableOrEnable {
             features: f,
index 5772b7e1d812afa3c2566ecb3fd31e042e078f80..ff111d96f840b1bc817ceb7bfbecf29aa1ee0e6d 100644 (file)
@@ -316,4 +316,19 @@ fn typeid_metadata(&self, typeid: String) -> &'ll Value {
             )
         }
     }
+
+    fn set_kcfi_type_metadata(&self, function: &'ll Value, kcfi_typeid: u32) {
+        let kcfi_type_metadata = self.const_u32(kcfi_typeid);
+        unsafe {
+            llvm::LLVMGlobalSetMetadata(
+                function,
+                llvm::MD_kcfi_type as c_uint,
+                llvm::LLVMMDNodeInContext2(
+                    self.llcx,
+                    &llvm::LLVMValueAsMetadata(kcfi_type_metadata),
+                    1,
+                ),
+            )
+        }
+    }
 }
index d868e3d56ba6b33d240fe92b65b7e003ebe45726..345174fb595ab1de60c74441c44e3481730bdb7c 100644 (file)
@@ -7,6 +7,7 @@ edition = "2021"
 test = false
 
 [dependencies]
+ar_archive_writer = "0.1.1"
 bitflags = "1.2.1"
 cc = "1.0.69"
 itertools = "0.10.1"
index 2b1b06d1644c9062656d3cc52ce816dc2bb72eff..58558fb8c4ba2912b53f7fcef66c10c676c4a7aa 100644 (file)
@@ -6,14 +6,19 @@
 
 use super::metadata::search_for_section;
 
+pub use ar_archive_writer::get_native_object_symbols;
+use ar_archive_writer::{write_archive_to_stream, ArchiveKind, NewArchiveMember};
 use object::read::archive::ArchiveFile;
+use object::read::macho::FatArch;
+use tempfile::Builder as TempFileBuilder;
 
 use std::error::Error;
 use std::fs::File;
-use std::io;
+use std::io::{self, Write};
 use std::path::{Path, PathBuf};
 
-use crate::errors::ExtractBundledLibsError;
+// Re-exporting for rustc_codegen_llvm::back::archive
+pub use crate::errors::{ArchiveBuildFailure, ExtractBundledLibsError, UnknownArchiveKind};
 
 pub trait ArchiveBuilderBuilder {
     fn new_archive_builder<'a>(&self, sess: &'a Session) -> Box<dyn ArchiveBuilder<'a> + 'a>;
@@ -80,3 +85,225 @@ fn add_archive(
 
     fn build(self: Box<Self>, output: &Path) -> bool;
 }
+
+#[must_use = "must call build() to finish building the archive"]
+pub struct ArArchiveBuilder<'a> {
+    sess: &'a Session,
+    get_object_symbols:
+        fn(buf: &[u8], f: &mut dyn FnMut(&[u8]) -> io::Result<()>) -> io::Result<bool>,
+
+    src_archives: Vec<(PathBuf, Mmap)>,
+    // Don't use an `HashMap` here, as the order is important. `lib.rmeta` needs
+    // to be at the end of an archive in some cases for linkers to not get confused.
+    entries: Vec<(Vec<u8>, ArchiveEntry)>,
+}
+
+#[derive(Debug)]
+enum ArchiveEntry {
+    FromArchive { archive_index: usize, file_range: (u64, u64) },
+    File(PathBuf),
+}
+
+impl<'a> ArArchiveBuilder<'a> {
+    pub fn new(
+        sess: &'a Session,
+        get_object_symbols: fn(
+            buf: &[u8],
+            f: &mut dyn FnMut(&[u8]) -> io::Result<()>,
+        ) -> io::Result<bool>,
+    ) -> ArArchiveBuilder<'a> {
+        ArArchiveBuilder { sess, get_object_symbols, src_archives: vec![], entries: vec![] }
+    }
+}
+
+fn try_filter_fat_archs(
+    archs: object::read::Result<&[impl FatArch]>,
+    target_arch: object::Architecture,
+    archive_path: &Path,
+    archive_map_data: &[u8],
+) -> io::Result<Option<PathBuf>> {
+    let archs = archs.map_err(|e| io::Error::new(io::ErrorKind::Other, e))?;
+
+    let desired = match archs.iter().filter(|a| a.architecture() == target_arch).next() {
+        Some(a) => a,
+        None => return Ok(None),
+    };
+
+    let (mut new_f, extracted_path) = tempfile::Builder::new()
+        .suffix(archive_path.file_name().unwrap())
+        .tempfile()?
+        .keep()
+        .unwrap();
+
+    new_f.write_all(
+        desired.data(archive_map_data).map_err(|e| io::Error::new(io::ErrorKind::Other, e))?,
+    )?;
+
+    Ok(Some(extracted_path))
+}
+
+pub fn try_extract_macho_fat_archive(
+    sess: &Session,
+    archive_path: &Path,
+) -> io::Result<Option<PathBuf>> {
+    let archive_map = unsafe { Mmap::map(File::open(&archive_path)?)? };
+    let target_arch = match sess.target.arch.as_ref() {
+        "aarch64" => object::Architecture::Aarch64,
+        "x86_64" => object::Architecture::X86_64,
+        _ => return Ok(None),
+    };
+
+    match object::macho::FatHeader::parse(&*archive_map) {
+        Ok(h) if h.magic.get(object::endian::BigEndian) == object::macho::FAT_MAGIC => {
+            let archs = object::macho::FatHeader::parse_arch32(&*archive_map);
+            try_filter_fat_archs(archs, target_arch, archive_path, &*archive_map)
+        }
+        Ok(h) if h.magic.get(object::endian::BigEndian) == object::macho::FAT_MAGIC_64 => {
+            let archs = object::macho::FatHeader::parse_arch64(&*archive_map);
+            try_filter_fat_archs(archs, target_arch, archive_path, &*archive_map)
+        }
+        // Not a FatHeader at all, just return None.
+        _ => Ok(None),
+    }
+}
+
+impl<'a> ArchiveBuilder<'a> for ArArchiveBuilder<'a> {
+    fn add_archive(
+        &mut self,
+        archive_path: &Path,
+        mut skip: Box<dyn FnMut(&str) -> bool + 'static>,
+    ) -> io::Result<()> {
+        let mut archive_path = archive_path.to_path_buf();
+        if self.sess.target.llvm_target.contains("-apple-macosx") {
+            if let Some(new_archive_path) =
+                try_extract_macho_fat_archive(&self.sess, &archive_path)?
+            {
+                archive_path = new_archive_path
+            }
+        }
+
+        if self.src_archives.iter().any(|archive| archive.0 == archive_path) {
+            return Ok(());
+        }
+
+        let archive_map = unsafe { Mmap::map(File::open(&archive_path)?)? };
+        let archive = ArchiveFile::parse(&*archive_map)
+            .map_err(|err| io::Error::new(io::ErrorKind::InvalidData, err))?;
+        let archive_index = self.src_archives.len();
+
+        for entry in archive.members() {
+            let entry = entry.map_err(|err| io::Error::new(io::ErrorKind::InvalidData, err))?;
+            let file_name = String::from_utf8(entry.name().to_vec())
+                .map_err(|err| io::Error::new(io::ErrorKind::InvalidData, err))?;
+            if !skip(&file_name) {
+                self.entries.push((
+                    file_name.into_bytes(),
+                    ArchiveEntry::FromArchive { archive_index, file_range: entry.file_range() },
+                ));
+            }
+        }
+
+        self.src_archives.push((archive_path.to_owned(), archive_map));
+        Ok(())
+    }
+
+    /// Adds an arbitrary file to this archive
+    fn add_file(&mut self, file: &Path) {
+        self.entries.push((
+            file.file_name().unwrap().to_str().unwrap().to_string().into_bytes(),
+            ArchiveEntry::File(file.to_owned()),
+        ));
+    }
+
+    /// Combine the provided files, rlibs, and native libraries into a single
+    /// `Archive`.
+    fn build(self: Box<Self>, output: &Path) -> bool {
+        let sess = self.sess;
+        match self.build_inner(output) {
+            Ok(any_members) => any_members,
+            Err(e) => sess.emit_fatal(ArchiveBuildFailure { error: e }),
+        }
+    }
+}
+
+impl<'a> ArArchiveBuilder<'a> {
+    fn build_inner(self, output: &Path) -> io::Result<bool> {
+        let archive_kind = match &*self.sess.target.archive_format {
+            "gnu" => ArchiveKind::Gnu,
+            "bsd" => ArchiveKind::Bsd,
+            "darwin" => ArchiveKind::Darwin,
+            "coff" => ArchiveKind::Coff,
+            kind => {
+                self.sess.emit_fatal(UnknownArchiveKind { kind });
+            }
+        };
+
+        let mut entries = Vec::new();
+
+        for (entry_name, entry) in self.entries {
+            let data =
+                match entry {
+                    ArchiveEntry::FromArchive { archive_index, file_range } => {
+                        let src_archive = &self.src_archives[archive_index];
+
+                        let data = &src_archive.1
+                            [file_range.0 as usize..file_range.0 as usize + file_range.1 as usize];
+
+                        Box::new(data) as Box<dyn AsRef<[u8]>>
+                    }
+                    ArchiveEntry::File(file) => unsafe {
+                        Box::new(
+                            Mmap::map(File::open(file).map_err(|err| {
+                                io_error_context("failed to open object file", err)
+                            })?)
+                            .map_err(|err| io_error_context("failed to map object file", err))?,
+                        ) as Box<dyn AsRef<[u8]>>
+                    },
+                };
+
+            entries.push(NewArchiveMember {
+                buf: data,
+                get_symbols: self.get_object_symbols,
+                member_name: String::from_utf8(entry_name).unwrap(),
+                mtime: 0,
+                uid: 0,
+                gid: 0,
+                perms: 0o644,
+            })
+        }
+
+        // Write to a temporary file first before atomically renaming to the final name.
+        // This prevents programs (including rustc) from attempting to read a partial archive.
+        // It also enables writing an archive with the same filename as a dependency on Windows as
+        // required by a test.
+        let mut archive_tmpfile = TempFileBuilder::new()
+            .suffix(".temp-archive")
+            .tempfile_in(output.parent().unwrap_or_else(|| Path::new("")))
+            .map_err(|err| io_error_context("couldn't create a temp file", err))?;
+
+        write_archive_to_stream(
+            archive_tmpfile.as_file_mut(),
+            &entries,
+            true,
+            archive_kind,
+            true,
+            false,
+        )?;
+
+        let any_entries = !entries.is_empty();
+        drop(entries);
+        // Drop src_archives to unmap all input archives, which is necessary if we want to write the
+        // output archive to the same location as an input archive on Windows.
+        drop(self.src_archives);
+
+        archive_tmpfile
+            .persist(output)
+            .map_err(|err| io_error_context("failed to rename archive file", err.error))?;
+
+        Ok(any_entries)
+    }
+}
+
+fn io_error_context(context: &str, err: io::Error) -> io::Error {
+    io::Error::new(io::ErrorKind::Other, format!("{context}: {err}"))
+}
index 7cb4f5503a101f1da94d1b78ed4020154c83317b..882430694e16d7f65668154330f9796d7f8ff924 100644 (file)
@@ -102,7 +102,7 @@ pub fn link_binary<'a>(
                 sess,
                 crate_type,
                 outputs,
-                codegen_results.crate_info.local_crate_name.as_str(),
+                codegen_results.crate_info.local_crate_name,
             );
             match crate_type {
                 CrateType::Rlib => {
@@ -2352,15 +2352,6 @@ fn add_native_libs_from_crate(
                                 &search_paths.get_or_init(|| archive_search_paths(sess)),
                             );
                         } else {
-                            // HACK/FIXME: Fixup a circular dependency between libgcc and libc
-                            // with glibc. This logic should be moved to the libc crate.
-                            if cnum != LOCAL_CRATE
-                                && sess.target.os == "linux"
-                                && sess.target.env == "gnu"
-                                && name == "c"
-                            {
-                                cmd.link_staticlib("gcc", false);
-                            }
                             cmd.link_staticlib(name, verbatim)
                         }
                     }
index 4f396e970ad70969228cae3756eec5273af4a483..664697e0edaa406f5018d4a014fe7973730785f8 100644 (file)
@@ -41,7 +41,6 @@
 use rustc_target::abi::{Align, Size, VariantIdx};
 
 use std::collections::BTreeSet;
-use std::convert::TryFrom;
 use std::time::{Duration, Instant};
 
 use itertools::Itertools;
index ade50af0aee8d7dabcc31b835100c55db03f2418..e3b6fbf1bc7f0e1bf07f39e7f6d581d1d8046427 100644 (file)
@@ -534,3 +534,17 @@ pub struct ReadFileError {
 #[derive(Diagnostic)]
 #[diag(codegen_ssa_unsupported_link_self_contained)]
 pub struct UnsupportedLinkSelfContained;
+
+#[derive(Diagnostic)]
+#[diag(codegen_ssa_archive_build_failure)]
+// Public for rustc_codegen_llvm::back::archive
+pub struct ArchiveBuildFailure {
+    pub error: std::io::Error,
+}
+
+#[derive(Diagnostic)]
+#[diag(codegen_ssa_unknown_archive_kind)]
+// Public for rustc_codegen_llvm::back::archive
+pub struct UnknownArchiveKind<'a> {
+    pub kind: &'a str,
+}
index 03d833fbba87cf4afbc49318c9fa55b52d8a57e3..f3f5ddb52d6a4a29117ee3ad4be87ccd99e4c763 100644 (file)
@@ -307,12 +307,10 @@ fn codegen_switchint_terminator(
         helper: TerminatorCodegenHelper<'tcx>,
         bx: &mut Bx,
         discr: &mir::Operand<'tcx>,
-        switch_ty: Ty<'tcx>,
         targets: &SwitchTargets,
     ) {
         let discr = self.codegen_operand(bx, &discr);
-        // `switch_ty` is redundant, sanity-check that.
-        assert_eq!(discr.layout.ty, switch_ty);
+        let switch_ty = discr.layout.ty;
         let mut target_iter = targets.iter();
         if target_iter.len() == 1 {
             // If there are two targets (one conditional, one fallback), emit `br` instead of
@@ -1293,8 +1291,8 @@ fn codegen_terminator(
                 helper.funclet_br(self, bx, target, mergeable_succ())
             }
 
-            mir::TerminatorKind::SwitchInt { ref discr, switch_ty, ref targets } => {
-                self.codegen_switchint_terminator(helper, bx, discr, switch_ty, targets);
+            mir::TerminatorKind::SwitchInt { ref discr, ref targets } => {
+                self.codegen_switchint_terminator(helper, bx, discr, targets);
                 MergingSucc::False
             }
 
index 99283d3bb29f44735efd789ebbe7e0417bc0c77e..b7982b633f57fa8b38b93983d078358152820d68 100644 (file)
@@ -3,12 +3,12 @@
 use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
 use rustc_middle::mir;
 use rustc_middle::ty;
+use rustc_middle::ty::layout::TyAndLayout;
 use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf};
 use rustc_session::config::DebugInfo;
 use rustc_span::symbol::{kw, Symbol};
 use rustc_span::{BytePos, Span};
-use rustc_target::abi::Abi;
-use rustc_target::abi::Size;
+use rustc_target::abi::{Abi, Size, VariantIdx};
 
 use super::operand::{OperandRef, OperandValue};
 use super::place::PlaceRef;
@@ -76,6 +76,106 @@ pub fn adjust_dbg_scope_for_span<Cx: CodegenMethods<'tcx, DIScope = S, DILocatio
     }
 }
 
+trait DebugInfoOffsetLocation<'tcx, Bx> {
+    fn deref(&self, bx: &mut Bx) -> Self;
+    fn layout(&self) -> TyAndLayout<'tcx>;
+    fn project_field(&self, bx: &mut Bx, field: mir::Field) -> Self;
+    fn downcast(&self, bx: &mut Bx, variant: VariantIdx) -> Self;
+}
+
+impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> DebugInfoOffsetLocation<'tcx, Bx>
+    for PlaceRef<'tcx, Bx::Value>
+{
+    fn deref(&self, bx: &mut Bx) -> Self {
+        bx.load_operand(*self).deref(bx.cx())
+    }
+
+    fn layout(&self) -> TyAndLayout<'tcx> {
+        self.layout
+    }
+
+    fn project_field(&self, bx: &mut Bx, field: mir::Field) -> Self {
+        PlaceRef::project_field(*self, bx, field.index())
+    }
+
+    fn downcast(&self, bx: &mut Bx, variant: VariantIdx) -> Self {
+        self.project_downcast(bx, variant)
+    }
+}
+
+impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> DebugInfoOffsetLocation<'tcx, Bx>
+    for TyAndLayout<'tcx>
+{
+    fn deref(&self, bx: &mut Bx) -> Self {
+        bx.cx().layout_of(
+            self.ty.builtin_deref(true).unwrap_or_else(|| bug!("cannot deref `{}`", self.ty)).ty,
+        )
+    }
+
+    fn layout(&self) -> TyAndLayout<'tcx> {
+        *self
+    }
+
+    fn project_field(&self, bx: &mut Bx, field: mir::Field) -> Self {
+        self.field(bx.cx(), field.index())
+    }
+
+    fn downcast(&self, bx: &mut Bx, variant: VariantIdx) -> Self {
+        self.for_variant(bx.cx(), variant)
+    }
+}
+
+struct DebugInfoOffset<T> {
+    /// Offset from the `base` used to calculate the debuginfo offset.
+    direct_offset: Size,
+    /// Each offset in this vector indicates one level of indirection from the base or previous
+    /// indirect offset plus a dereference.
+    indirect_offsets: Vec<Size>,
+    /// The final location debuginfo should point to.
+    result: T,
+}
+
+fn calculate_debuginfo_offset<
+    'a,
+    'tcx,
+    Bx: BuilderMethods<'a, 'tcx>,
+    L: DebugInfoOffsetLocation<'tcx, Bx>,
+>(
+    bx: &mut Bx,
+    local: mir::Local,
+    var: &PerLocalVarDebugInfo<'tcx, Bx::DIVariable>,
+    base: L,
+) -> DebugInfoOffset<L> {
+    let mut direct_offset = Size::ZERO;
+    // FIXME(eddyb) use smallvec here.
+    let mut indirect_offsets = vec![];
+    let mut place = base;
+
+    for elem in &var.projection[..] {
+        match *elem {
+            mir::ProjectionElem::Deref => {
+                indirect_offsets.push(Size::ZERO);
+                place = place.deref(bx);
+            }
+            mir::ProjectionElem::Field(field, _) => {
+                let offset = indirect_offsets.last_mut().unwrap_or(&mut direct_offset);
+                *offset += place.layout().fields.offset(field.index());
+                place = place.project_field(bx, field);
+            }
+            mir::ProjectionElem::Downcast(_, variant) => {
+                place = place.downcast(bx, variant);
+            }
+            _ => span_bug!(
+                var.source_info.span,
+                "unsupported var debuginfo place `{:?}`",
+                mir::Place { local, projection: var.projection },
+            ),
+        }
+    }
+
+    DebugInfoOffset { direct_offset, indirect_offsets, result: place }
+}
+
 impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
     pub fn set_debug_loc(&self, bx: &mut Bx, source_info: mir::SourceInfo) {
         bx.set_span(source_info.span);
@@ -262,33 +362,8 @@ pub fn debug_introduce_local(&self, bx: &mut Bx, local: mir::Local) {
             let Some(dbg_var) = var.dbg_var else { continue };
             let Some(dbg_loc) = self.dbg_loc(var.source_info) else { continue };
 
-            let mut direct_offset = Size::ZERO;
-            // FIXME(eddyb) use smallvec here.
-            let mut indirect_offsets = vec![];
-            let mut place = base;
-
-            for elem in &var.projection[..] {
-                match *elem {
-                    mir::ProjectionElem::Deref => {
-                        indirect_offsets.push(Size::ZERO);
-                        place = bx.load_operand(place).deref(bx.cx());
-                    }
-                    mir::ProjectionElem::Field(field, _) => {
-                        let i = field.index();
-                        let offset = indirect_offsets.last_mut().unwrap_or(&mut direct_offset);
-                        *offset += place.layout.fields.offset(i);
-                        place = place.project_field(bx, i);
-                    }
-                    mir::ProjectionElem::Downcast(_, variant) => {
-                        place = place.project_downcast(bx, variant);
-                    }
-                    _ => span_bug!(
-                        var.source_info.span,
-                        "unsupported var debuginfo place `{:?}`",
-                        mir::Place { local, projection: var.projection },
-                    ),
-                }
-            }
+            let DebugInfoOffset { direct_offset, indirect_offsets, result: _ } =
+                calculate_debuginfo_offset(bx, local, &var, base.layout);
 
             // When targeting MSVC, create extra allocas for arguments instead of pointing multiple
             // dbg_var_addr() calls into the same alloca with offsets. MSVC uses CodeView records
@@ -306,6 +381,9 @@ pub fn debug_introduce_local(&self, bx: &mut Bx, local: mir::Local) {
                     || !matches!(&indirect_offsets[..], [Size::ZERO] | []));
 
             if should_create_individual_allocas {
+                let DebugInfoOffset { direct_offset: _, indirect_offsets: _, result: place } =
+                    calculate_debuginfo_offset(bx, local, &var, base);
+
                 // Create a variable which will be a pointer to the actual value
                 let ptr_ty = bx.tcx().mk_ty(ty::RawPtr(ty::TypeAndMut {
                     mutbl: mir::Mutability::Mut,
index 908555385891d85417e4710ad4b860b790e43676..fbe30154a7c8d26b23cb4af4ac5fa419e2a558ad 100644 (file)
@@ -309,14 +309,14 @@ pub fn codegen_get_discr<Bx: BuilderMethods<'a, 'tcx, Value = V>>(
                 // In the algorithm above, we can change
                 // cast(relative_tag) + niche_variants.start()
                 // into
-                // cast(tag) + (niche_variants.start() - niche_start)
+                // cast(tag + (niche_variants.start() - niche_start))
                 // if either the casted type is no larger than the original
                 // type, or if the niche values are contiguous (in either the
                 // signed or unsigned sense).
-                let can_incr_after_cast = cast_smaller || niches_ule || niches_sle;
+                let can_incr = cast_smaller || niches_ule || niches_sle;
 
                 let data_for_boundary_niche = || -> Option<(IntPredicate, u128)> {
-                    if !can_incr_after_cast {
+                    if !can_incr {
                         None
                     } else if niche_start == low_unsigned {
                         Some((IntPredicate::IntULE, niche_end))
@@ -353,24 +353,33 @@ pub fn codegen_get_discr<Bx: BuilderMethods<'a, 'tcx, Value = V>>(
                     // The algorithm is now this:
                     // is_niche = tag <= niche_end
                     // discr = if is_niche {
-                    //     cast(tag) + (niche_variants.start() - niche_start)
+                    //     cast(tag + (niche_variants.start() - niche_start))
                     // } else {
                     //     untagged_variant
                     // }
                     // (the first line may instead be tag >= niche_start,
                     // and may be a signed or unsigned comparison)
+                    // The arithmetic must be done before the cast, so we can
+                    // have the correct wrapping behavior. See issue #104519 for
+                    // the consequences of getting this wrong.
                     let is_niche =
                         bx.icmp(predicate, tag, bx.cx().const_uint_big(tag_llty, constant));
+                    let delta = (niche_variants.start().as_u32() as u128).wrapping_sub(niche_start);
+                    let incr_tag = if delta == 0 {
+                        tag
+                    } else {
+                        bx.add(tag, bx.cx().const_uint_big(tag_llty, delta))
+                    };
+
                     let cast_tag = if cast_smaller {
-                        bx.intcast(tag, cast_to, false)
+                        bx.intcast(incr_tag, cast_to, false)
                     } else if niches_ule {
-                        bx.zext(tag, cast_to)
+                        bx.zext(incr_tag, cast_to)
                     } else {
-                        bx.sext(tag, cast_to)
+                        bx.sext(incr_tag, cast_to)
                     };
 
-                    let delta = (niche_variants.start().as_u32() as u128).wrapping_sub(niche_start);
-                    (is_niche, cast_tag, delta)
+                    (is_niche, cast_tag, 0)
                 } else {
                     // The special cases don't apply, so we'll have to go with
                     // the general algorithm.
index 86481d5d758d6d251c5b916163079905a8dd805f..109161ccc836865e36ea8151bc61f236125347db 100644 (file)
@@ -122,6 +122,7 @@ fn scalar_pair_element_backend_type(
 pub trait TypeMembershipMethods<'tcx>: Backend<'tcx> {
     fn set_type_metadata(&self, function: Self::Function, typeid: String);
     fn typeid_metadata(&self, typeid: String) -> Self::Value;
+    fn set_kcfi_type_metadata(&self, function: Self::Function, typeid: u32);
 }
 
 pub trait ArgAbiMethods<'tcx>: HasCodegen<'tcx> {
index e3dfd72d5f0e3ff60dba77499174cb40d443ad1a..c60d6e4fed9f55277ba8640f9fb8ed81d4612dfc 100644 (file)
@@ -123,14 +123,14 @@ pub(super) fn report_decorated(
                 // Helper closure to print duplicated lines.
                 let mut flush_last_line = |last_frame, times| {
                     if let Some((line, span)) = last_frame {
-                        err.span_label(span, &line);
+                        err.span_note(span, &line);
                         // Don't print [... additional calls ...] if the number of lines is small
                         if times < 3 {
                             for _ in 0..times {
-                                err.span_label(span, &line);
+                                err.span_note(span, &line);
                             }
                         } else {
-                            err.span_label(
+                            err.span_note(
                                 span,
                                 format!("[... {} additional calls {} ...]", times, &line),
                             );
index c27790d8887a377a67a59da57daa99ca84f5f9b3..319f2b2c25ebf320f71c6d0fe83bca042fe3f191 100644 (file)
@@ -1,5 +1,4 @@
 use std::borrow::Cow;
-use std::convert::TryInto;
 
 use either::{Left, Right};
 
index 04e68b96455251c2eeaa8651be41b7c88685b78f..3dfded2d930a052c305859ed257536285303eda8 100644 (file)
@@ -240,7 +240,7 @@ fn align_offset(
                     let align = ImmTy::from_uint(target_align, args[1].layout).into();
                     let fn_abi = self.fn_abi_of_instance(instance, ty::List::empty())?;
 
-                    // We replace the entire entire function call with a "tail call".
+                    // We replace the entire function call with a "tail call".
                     // Note that this happens before the frame of the original function
                     // is pushed on the stack.
                     self.eval_fn_call(
index 269ae15d4974547f929544764313ce900982ecc0..b1fdeb01b100abd58f5b0b44c678b07ffc2ebe75 100644 (file)
@@ -1,5 +1,4 @@
 use std::assert_matches::assert_matches;
-use std::convert::TryFrom;
 
 use rustc_apfloat::ieee::{Double, Single};
 use rustc_apfloat::{Float, FloatConvert};
index 79450fccfc4d8567e377320463034e0ebef3f15d..0b2809f1d2c285238c1a93a8bb65fc314483de87 100644 (file)
@@ -17,7 +17,7 @@
 };
 use rustc_mir_dataflow::storage::always_storage_live_locals;
 use rustc_session::Limit;
-use rustc_span::{Pos, Span};
+use rustc_span::Span;
 use rustc_target::abi::{call::FnAbi, Align, HasDataLayout, Size, TargetDataLayout};
 
 use super::{
@@ -256,25 +256,13 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
             if tcx.def_key(self.instance.def_id()).disambiguated_data.data
                 == DefPathData::ClosureExpr
             {
-                write!(f, "inside closure")?;
+                write!(f, "inside closure")
             } else {
                 // Note: this triggers a `good_path_bug` state, which means that if we ever get here
                 // we must emit a diagnostic. We should never display a `FrameInfo` unless we
                 // actually want to emit a warning or error to the user.
-                write!(f, "inside `{}`", self.instance)?;
+                write!(f, "inside `{}`", self.instance)
             }
-            if !self.span.is_dummy() {
-                let sm = tcx.sess.source_map();
-                let lo = sm.lookup_char_pos(self.span.lo());
-                write!(
-                    f,
-                    " at {}:{}:{}",
-                    sm.filename_for_diagnostics(&lo.file.name),
-                    lo.line,
-                    lo.col.to_usize() + 1
-                )?;
-            }
-            Ok(())
         })
     }
 }
@@ -676,6 +664,10 @@ pub fn push_stack_frame(
         return_to_block: StackPopCleanup,
     ) -> InterpResult<'tcx> {
         trace!("body: {:#?}", body);
+        // Clobber previous return place contents, nobody is supposed to be able to see them any more
+        // This also checks dereferenceable, but not align. We rely on all constructed places being
+        // sufficiently aligned (in particular we rely on `deref_operand` checking alignment).
+        self.write_uninit(return_place)?;
         // first push a stack frame so we have access to the local substs
         let pre_frame = Frame {
             body,
index 7940efcd2b11f1517a22631f0d5a4d77616ece7d..b9be7fa48000be54ddef02808aa26b3a100ec2fb 100644 (file)
@@ -2,8 +2,6 @@
 //! looking at their MIR. Intrinsics/functions supported here are shared by CTFE
 //! and miri.
 
-use std::convert::TryFrom;
-
 use rustc_hir::def_id::DefId;
 use rustc_middle::mir::{
     self,
index 7d94a22c43d71e467d3c8eeed2963ebc0dbcbff4..77c7b4bacb8c8a96d68b42704478166e754d0772 100644 (file)
@@ -1,5 +1,3 @@
-use std::convert::TryFrom;
-
 use rustc_ast::Mutability;
 use rustc_hir::lang_items::LangItem;
 use rustc_middle::mir::TerminatorKind;
index 88d25be6bd861d66f8a0788b5a9243ebdf7b105b..0604d5ee6fa4c93e94211111da45abd2e4715f15 100644 (file)
@@ -373,9 +373,21 @@ fn before_memory_deallocation(
         Ok(())
     }
 
-    /// Executes a retagging operation.
+    /// Executes a retagging operation for a single pointer.
+    /// Returns the possibly adjusted pointer.
     #[inline]
-    fn retag(
+    fn retag_ptr_value(
+        _ecx: &mut InterpCx<'mir, 'tcx, Self>,
+        _kind: mir::RetagKind,
+        val: &ImmTy<'tcx, Self::Provenance>,
+    ) -> InterpResult<'tcx, ImmTy<'tcx, Self::Provenance>> {
+        Ok(val.clone())
+    }
+
+    /// Executes a retagging operation on a compound value.
+    /// Replaces all pointers stored in the given place.
+    #[inline]
+    fn retag_place_contents(
         _ecx: &mut InterpCx<'mir, 'tcx, Self>,
         _kind: mir::RetagKind,
         _place: &PlaceTy<'tcx, Self::Provenance>,
index 1f1d0665139d093f005f9c0a81edd2e6d0c7c19a..949f95c5fa81c2a8909ac6fd353b8578946b9535 100644 (file)
@@ -1,5 +1,3 @@
-use std::convert::TryFrom;
-
 use rustc_apfloat::Float;
 use rustc_middle::mir;
 use rustc_middle::mir::interpret::{InterpResult, Scalar};
index 60578246eedcccb01cf885385d53caa5839602f7..81b44a49484d0a72e213d8a32b510e784b7938b1 100644 (file)
@@ -8,7 +8,7 @@
 use rustc_middle::mir::interpret::{InterpResult, Scalar};
 use rustc_middle::ty::layout::LayoutOf;
 
-use super::{InterpCx, Machine};
+use super::{ImmTy, InterpCx, Machine};
 
 /// Classify whether an operator is "left-homogeneous", i.e., the LHS has the
 /// same type as the result.
@@ -108,7 +108,7 @@ pub fn statement(&mut self, stmt: &mir::Statement<'tcx>) -> InterpResult<'tcx> {
             // Stacked Borrows.
             Retag(kind, place) => {
                 let dest = self.eval_place(**place)?;
-                M::retag(self, *kind, &dest)?;
+                M::retag_place_contents(self, *kind, &dest)?;
             }
 
             Intrinsic(box ref intrinsic) => self.emulate_nondiverging_intrinsic(intrinsic)?,
@@ -247,10 +247,41 @@ pub fn eval_rvalue_into_place(
                 self.write_scalar(Scalar::from_machine_usize(len, self), &dest)?;
             }
 
-            AddressOf(_, place) | Ref(_, _, place) => {
+            Ref(_, borrow_kind, place) => {
                 let src = self.eval_place(place)?;
                 let place = self.force_allocation(&src)?;
-                self.write_immediate(place.to_ref(self), &dest)?;
+                let val = ImmTy::from_immediate(place.to_ref(self), dest.layout);
+                // A fresh reference was created, make sure it gets retagged.
+                let val = M::retag_ptr_value(
+                    self,
+                    if borrow_kind.allows_two_phase_borrow() {
+                        mir::RetagKind::TwoPhase
+                    } else {
+                        mir::RetagKind::Default
+                    },
+                    &val,
+                )?;
+                self.write_immediate(*val, &dest)?;
+            }
+
+            AddressOf(_, place) => {
+                // Figure out whether this is an addr_of of an already raw place.
+                let place_base_raw = if place.has_deref() {
+                    let ty = self.frame().body.local_decls[place.local].ty;
+                    ty.is_unsafe_ptr()
+                } else {
+                    // Not a deref, and thus not raw.
+                    false
+                };
+
+                let src = self.eval_place(place)?;
+                let place = self.force_allocation(&src)?;
+                let mut val = ImmTy::from_immediate(place.to_ref(self), dest.layout);
+                if !place_base_raw {
+                    // If this was not already raw, it needs retagging.
+                    val = M::retag_ptr_value(self, mir::RetagKind::Raw, &val)?;
+                }
+                self.write_immediate(*val, &dest)?;
             }
 
             NullaryOp(null_op, ty) => {
index 57e40e168fa48e0b281541ee9beaef7ce7293f95..0e7ffcdffc97aae54f0b020282f3b61aa9dfa701 100644 (file)
@@ -29,10 +29,9 @@ pub(super) fn eval_terminator(
 
             Goto { target } => self.go_to_block(target),
 
-            SwitchInt { ref discr, ref targets, switch_ty } => {
+            SwitchInt { ref discr, ref targets } => {
                 let discr = self.read_immediate(&self.eval_operand(discr, None)?)?;
                 trace!("SwitchInt({:?})", *discr);
-                assert_eq!(discr.layout.ty, switch_ty);
 
                 // Branch to the `otherwise` case by default, if no match is found.
                 let mut target_block = targets.otherwise();
index 2bc521d5bbe0b8bca7c3ea812ee8f8d9bd38c0ba..e4f716c31945c68aacdfce6490c13a7116824508 100644 (file)
@@ -1,6 +1,5 @@
 use rustc_middle::mir::interpret::InterpResult;
 use rustc_middle::ty::{self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor};
-use std::convert::TryInto;
 use std::ops::ControlFlow;
 
 /// Checks whether a type contains generic parameters which require substitution.
index 0e85c7d11bce560b3af9d507a25f23b2e0aa0eaf..fc65306e440a9912ead726d9d4ca871cd5eae3be 100644 (file)
@@ -4,7 +4,6 @@
 //! That's useful because it means other passes (e.g. promotion) can rely on `const`s
 //! to be const-safe.
 
-use std::convert::TryFrom;
 use std::fmt::{Display, Write};
 use std::num::NonZeroUsize;
 
index f48bcd9080966dafe2d693b828bb04aee3aafc69..6777fae74f1ca5d00018354072ef0ef5c15e62c3 100644 (file)
@@ -318,14 +318,14 @@ fn validate_place(&mut self, place: PlaceRef<'tcx>) -> Result<(), Unpromotable>
                 match elem {
                     ProjectionElem::Deref => {
                         let mut promotable = false;
+                        // When a static is used by-value, that gets desugared to `*STATIC_ADDR`,
+                        // and we need to be able to promote this. So check if this deref matches
+                        // that specific pattern.
+
                         // We need to make sure this is a `Deref` of a local with no further projections.
                         // Discussion can be found at
                         // https://github.com/rust-lang/rust/pull/74945#discussion_r463063247
                         if let Some(local) = place_base.as_local() {
-                            // This is a special treatment for cases like *&STATIC where STATIC is a
-                            // global static variable.
-                            // This pattern is generated only when global static variables are directly
-                            // accessed and is qualified for promotion safely.
                             if let TempState::Defined { location, .. } = self.temps[local] {
                                 let def_stmt = self.body[location.block]
                                     .statements
index bf700d3122465c584b1d15efc54a71ffe1ab88e1..64318f5f54d5d061c255726f800e9251d631933b 100644 (file)
@@ -2,6 +2,7 @@
 
 use rustc_data_structures::fx::FxHashSet;
 use rustc_index::bit_set::BitSet;
+use rustc_infer::traits::Reveal;
 use rustc_middle::mir::interpret::Scalar;
 use rustc_middle::mir::visit::NonUseContext::VarDebugInfo;
 use rustc_middle::mir::visit::{PlaceContext, Visitor};
@@ -44,8 +45,11 @@ fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
             return;
         }
         let def_id = body.source.def_id();
-        let param_env = tcx.param_env(def_id);
         let mir_phase = self.mir_phase;
+        let param_env = match mir_phase.reveal() {
+            Reveal::UserFacing => tcx.param_env(def_id),
+            Reveal::All => tcx.param_env_reveal_all_normalized(def_id),
+        };
 
         let always_live_locals = always_storage_live_locals(body);
         let storage_liveness = MaybeStorageLive::new(always_live_locals)
@@ -682,17 +686,8 @@ fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location
             TerminatorKind::Goto { target } => {
                 self.check_edge(location, *target, EdgeKind::Normal);
             }
-            TerminatorKind::SwitchInt { targets, switch_ty, discr } => {
-                let ty = discr.ty(&self.body.local_decls, self.tcx);
-                if ty != *switch_ty {
-                    self.fail(
-                        location,
-                        format!(
-                            "encountered `SwitchInt` terminator with type mismatch: {:?} != {:?}",
-                            ty, switch_ty,
-                        ),
-                    );
-                }
+            TerminatorKind::SwitchInt { targets, discr } => {
+                let switch_ty = discr.ty(&self.body.local_decls, self.tcx);
 
                 let target_width = self.tcx.sess.target.pointer_width;
 
index c43de3368c62fd190ec6e242e287803f9a2b1d78..10783c5ed1d1cd7389fd67f5aa72e83f74763108 100644 (file)
@@ -3,7 +3,6 @@
 use rustc_middle::ty::{Ty, TyCtxt};
 use rustc_target::abi::VariantIdx;
 
-use std::convert::TryFrom;
 use std::iter::TrustedLen;
 
 /// Expand `lhs = Rvalue::Aggregate(kind, operands)` into assignments to the fields.
index a39178016ce20617dda20a517959ae7843ade27b..b6e866f15efe3c576285798a16b4d9ce9d051afb 100644 (file)
@@ -1,6 +1,5 @@
 use crate::stable_hasher;
 use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
-use std::convert::TryInto;
 use std::hash::{Hash, Hasher};
 
 #[cfg(test)]
@@ -140,7 +139,7 @@ fn finish(hasher: stable_hasher::StableHasher) -> Self {
     }
 }
 
-impl_stable_hash_via_hash!(Fingerprint);
+impl_stable_traits_for_trivial_type!(Fingerprint);
 
 impl<E: Encoder> Encodable<E> for Fingerprint {
     #[inline]
index 7099ca7eb88c2db01f8b5ed0af656a99e6bca869..b31092eca9837bb0a0c5536b1be7e05c188fcbf5 100644 (file)
@@ -9,7 +9,6 @@
 use crate::graph::vec_graph::VecGraph;
 use crate::graph::{DirectedGraph, GraphSuccessors, WithNumEdges, WithNumNodes, WithSuccessors};
 use rustc_index::vec::{Idx, IndexVec};
-use std::cmp::Ord;
 use std::ops::Range;
 
 #[cfg(test)]
index e8efbd09a2c38c815647ec4cd62b5acae103bbc7..94232bb7626ec885327699322d6d1357b4a9da40 100644 (file)
@@ -1,5 +1,3 @@
-use std::cmp::Ord;
-
 use crate::graph::{DirectedGraph, GraphSuccessors, WithNumEdges, WithNumNodes, WithSuccessors};
 use rustc_index::vec::{Idx, IndexVec};
 
index 11cbff8ea6a84ef7d27adf4a266866a3409848ec..ba94f3776eb90bc5da1e4e534508d689aa20dda7 100644 (file)
@@ -4,8 +4,6 @@
 use std::ops::Deref;
 use std::ptr;
 
-use crate::fingerprint::Fingerprint;
-
 mod private {
     #[derive(Clone, Copy, Debug)]
     pub struct PrivateZst;
@@ -72,7 +70,7 @@ fn partial_cmp(&self, other: &Interned<'a, T>) -> Option<Ordering> {
         if ptr::eq(self.0, other.0) {
             Some(Ordering::Equal)
         } else {
-            let res = self.0.partial_cmp(&other.0);
+            let res = self.0.partial_cmp(other.0);
             debug_assert_ne!(res, Some(Ordering::Equal));
             res
         }
@@ -86,7 +84,7 @@ fn cmp(&self, other: &Interned<'a, T>) -> Ordering {
         if ptr::eq(self.0, other.0) {
             Ordering::Equal
         } else {
-            let res = self.0.cmp(&other.0);
+            let res = self.0.cmp(other.0);
             debug_assert_ne!(res, Ordering::Equal);
             res
         }
@@ -110,86 +108,5 @@ fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) {
     }
 }
 
-/// A helper type that you can wrap round your own type in order to automatically
-/// cache the stable hash on creation and not recompute it whenever the stable hash
-/// of the type is computed.
-/// This is only done in incremental mode. You can also opt out of caching by using
-/// StableHash::ZERO for the hash, in which case the hash gets computed each time.
-/// This is useful if you have values that you intern but never (can?) use for stable
-/// hashing.
-#[derive(Copy, Clone)]
-pub struct WithStableHash<T> {
-    pub internee: T,
-    pub stable_hash: Fingerprint,
-}
-
-impl<T: PartialEq> PartialEq for WithStableHash<T> {
-    #[inline]
-    fn eq(&self, other: &Self) -> bool {
-        self.internee.eq(&other.internee)
-    }
-}
-
-impl<T: Eq> Eq for WithStableHash<T> {}
-
-impl<T: Ord> PartialOrd for WithStableHash<T> {
-    fn partial_cmp(&self, other: &WithStableHash<T>) -> Option<Ordering> {
-        Some(self.internee.cmp(&other.internee))
-    }
-}
-
-impl<T: Ord> Ord for WithStableHash<T> {
-    fn cmp(&self, other: &WithStableHash<T>) -> Ordering {
-        self.internee.cmp(&other.internee)
-    }
-}
-
-impl<T> Deref for WithStableHash<T> {
-    type Target = T;
-
-    #[inline]
-    fn deref(&self) -> &T {
-        &self.internee
-    }
-}
-
-impl<T: Hash> Hash for WithStableHash<T> {
-    #[inline]
-    fn hash<H: Hasher>(&self, s: &mut H) {
-        if self.stable_hash != Fingerprint::ZERO {
-            self.stable_hash.hash(s)
-        } else {
-            self.internee.hash(s)
-        }
-    }
-}
-
-impl<T: HashStable<CTX>, CTX> HashStable<CTX> for WithStableHash<T> {
-    fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) {
-        if self.stable_hash == Fingerprint::ZERO || cfg!(debug_assertions) {
-            // No cached hash available. This can only mean that incremental is disabled.
-            // We don't cache stable hashes in non-incremental mode, because they are used
-            // so rarely that the performance actually suffers.
-
-            // We need to build the hash as if we cached it and then hash that hash, as
-            // otherwise the hashes will differ between cached and non-cached mode.
-            let stable_hash: Fingerprint = {
-                let mut hasher = StableHasher::new();
-                self.internee.hash_stable(hcx, &mut hasher);
-                hasher.finish()
-            };
-            if cfg!(debug_assertions) && self.stable_hash != Fingerprint::ZERO {
-                assert_eq!(
-                    stable_hash, self.stable_hash,
-                    "cached stable hash does not match freshly computed stable hash"
-                );
-            }
-            stable_hash.hash_stable(hcx, hasher);
-        } else {
-            self.stable_hash.hash_stable(hcx, hasher);
-        }
-    }
-}
-
 #[cfg(test)]
 mod tests;
index 917416df6b86703602d642c901aed666763a98d3..3d44e17f31d1fb81ed10f0bf3fb4f0745283a614 100644 (file)
@@ -36,6 +36,12 @@ impl Deref for Mmap {
 
     #[inline]
     fn deref(&self) -> &[u8] {
+        &self.0
+    }
+}
+
+impl AsRef<[u8]> for Mmap {
+    fn as_ref(&self) -> &[u8] {
         &*self.0
     }
 }
@@ -96,13 +102,13 @@ impl Deref for MmapMut {
 
     #[inline]
     fn deref(&self) -> &[u8] {
-        &*self.0
+        &self.0
     }
 }
 
 impl DerefMut for MmapMut {
     #[inline]
     fn deref_mut(&mut self) -> &mut [u8] {
-        &mut *self.0
+        &mut self.0
     }
 }
index ed5e566184f12922491d15a83544e0924d93e352..d1d92b905b82e0b9da4db953f10c263d8bce4838 100644 (file)
@@ -867,11 +867,9 @@ pub fn try_new<F, E>(o: O, f: F) -> Result<Self, E>
 /////////////////////////////////////////////////////////////////////////////
 
 use std::borrow::Borrow;
-use std::cmp::{Eq, Ord, Ordering, PartialEq, PartialOrd};
-use std::convert::From;
+use std::cmp::Ordering;
 use std::fmt::{self, Debug};
 use std::hash::{Hash, Hasher};
-use std::marker::{Send, Sync};
 
 impl<O, T: ?Sized> Deref for OwningRef<O, T> {
     type Target = T;
@@ -899,25 +897,25 @@ unsafe impl<O, T: ?Sized> StableAddress for OwningRef<O, T> {}
 
 impl<O, T: ?Sized> AsRef<T> for OwningRef<O, T> {
     fn as_ref(&self) -> &T {
-        &*self
+        self
     }
 }
 
 impl<O, T: ?Sized> AsRef<T> for OwningRefMut<O, T> {
     fn as_ref(&self) -> &T {
-        &*self
+        self
     }
 }
 
 impl<O, T: ?Sized> AsMut<T> for OwningRefMut<O, T> {
     fn as_mut(&mut self) -> &mut T {
-        &mut *self
+        self
     }
 }
 
 impl<O, T: ?Sized> Borrow<T> for OwningRef<O, T> {
     fn borrow(&self) -> &T {
-        &*self
+        self
     }
 }
 
@@ -1021,7 +1019,7 @@ impl<O, T: ?Sized> PartialEq for OwningRef<O, T>
     T: PartialEq,
 {
     fn eq(&self, other: &Self) -> bool {
-        (&*self as &T).eq(&*other as &T)
+        self.deref().eq(other.deref())
     }
 }
 
@@ -1032,7 +1030,7 @@ impl<O, T: ?Sized> PartialOrd for OwningRef<O, T>
     T: PartialOrd,
 {
     fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
-        (&*self as &T).partial_cmp(&*other as &T)
+        self.deref().partial_cmp(other.deref())
     }
 }
 
@@ -1041,7 +1039,7 @@ impl<O, T: ?Sized> Ord for OwningRef<O, T>
     T: Ord,
 {
     fn cmp(&self, other: &Self) -> Ordering {
-        (&*self as &T).cmp(&*other as &T)
+        self.deref().cmp(other.deref())
     }
 }
 
@@ -1050,7 +1048,7 @@ impl<O, T: ?Sized> Hash for OwningRef<O, T>
     T: Hash,
 {
     fn hash<H: Hasher>(&self, state: &mut H) {
-        (&*self as &T).hash(state);
+        self.deref().hash(state);
     }
 }
 
@@ -1059,7 +1057,7 @@ impl<O, T: ?Sized> PartialEq for OwningRefMut<O, T>
     T: PartialEq,
 {
     fn eq(&self, other: &Self) -> bool {
-        (&*self as &T).eq(&*other as &T)
+        self.deref().eq(other.deref())
     }
 }
 
@@ -1070,7 +1068,7 @@ impl<O, T: ?Sized> PartialOrd for OwningRefMut<O, T>
     T: PartialOrd,
 {
     fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
-        (&*self as &T).partial_cmp(&*other as &T)
+        self.deref().partial_cmp(other.deref())
     }
 }
 
@@ -1079,7 +1077,7 @@ impl<O, T: ?Sized> Ord for OwningRefMut<O, T>
     T: Ord,
 {
     fn cmp(&self, other: &Self) -> Ordering {
-        (&*self as &T).cmp(&*other as &T)
+        self.deref().cmp(other.deref())
     }
 }
 
@@ -1088,7 +1086,7 @@ impl<O, T: ?Sized> Hash for OwningRefMut<O, T>
     T: Hash,
 {
     fn hash<H: Hasher>(&self, state: &mut H) {
-        (&*self as &T).hash(state);
+        self.deref().hash(state);
     }
 }
 
@@ -1096,7 +1094,6 @@ fn hash<H: Hasher>(&self, state: &mut H) {
 // std types integration and convenience type defs
 /////////////////////////////////////////////////////////////////////////////
 
-use std::boxed::Box;
 use std::cell::{Ref, RefCell, RefMut};
 use std::rc::Rc;
 use std::sync::Arc;
index 320c03d5139f4ba0985dbaae066f61c3b92c0fe8..a9b187c4ce0a79f979ae4c562ebe56ab598c40bb 100644 (file)
@@ -3,7 +3,7 @@
 mod owning_ref {
     use super::super::OwningRef;
     use super::super::{BoxRef, Erased, ErasedBoxRef, RcRef};
-    use std::cmp::{Ord, Ordering, PartialEq, PartialOrd};
+    use std::cmp::Ordering;
     use std::collections::hash_map::DefaultHasher;
     use std::collections::HashMap;
     use std::hash::{Hash, Hasher};
@@ -368,7 +368,7 @@ fn owning_handle_safe_2() {
 mod owning_ref_mut {
     use super::super::BoxRef;
     use super::super::{BoxRefMut, Erased, ErasedBoxRefMut, OwningRefMut};
-    use std::cmp::{Ord, Ordering, PartialEq, PartialOrd};
+    use std::cmp::Ordering;
     use std::collections::hash_map::DefaultHasher;
     use std::collections::HashMap;
     use std::hash::{Hash, Hasher};
index ba1960805d84bf0301539f5e50363a8859db4c9d..1d4014f05acdc3e5a208d301ebd534a504fb411c 100644 (file)
@@ -86,7 +86,6 @@
 
 use std::borrow::Borrow;
 use std::collections::hash_map::Entry;
-use std::convert::Into;
 use std::error::Error;
 use std::fs;
 use std::path::Path;
@@ -192,7 +191,7 @@ fn cold_call<F>(profiler_ref: &SelfProfilerRef, f: F) -> TimingGuard<'_>
             F: for<'a> FnOnce(&'a SelfProfiler) -> TimingGuard<'a>,
         {
             let profiler = profiler_ref.profiler.as_ref().unwrap();
-            f(&**profiler)
+            f(profiler)
         }
 
         if self.event_filter_mask.contains(event_filter) {
@@ -466,7 +465,7 @@ fn instant_query_event(
 
     pub fn with_profiler(&self, f: impl FnOnce(&SelfProfiler)) {
         if let Some(profiler) = &self.profiler {
-            f(&profiler)
+            f(profiler)
         }
     }
 
@@ -733,7 +732,7 @@ fn drop(&mut self) {
         if let Some((start_time, start_rss, ref message)) = self.start_and_message {
             let end_rss = get_resident_set_size();
             let dur = start_time.elapsed();
-            print_time_passes_entry(&message, dur, start_rss, end_rss);
+            print_time_passes_entry(message, dur, start_rss, end_rss);
         }
     }
 }
index d607a5c8314e15d3d5cf091b9464c2c38dc47b21..03ff5e5b3751fe502d5c1c3c0265dc9c07c74aa8 100644 (file)
@@ -1,7 +1,6 @@
-use crate::stable_hasher::{HashStable, StableHasher};
+use crate::stable_hasher::{HashStable, StableHasher, StableOrd};
 use std::borrow::Borrow;
 use std::cmp::Ordering;
-use std::iter::FromIterator;
 use std::mem;
 use std::ops::{Bound, Index, IndexMut, RangeBounds};
 
@@ -308,7 +307,7 @@ fn from_iter<T: IntoIterator<Item = (K, V)>>(iter: T) -> Self {
     }
 }
 
-impl<K: HashStable<CTX>, V: HashStable<CTX>, CTX> HashStable<CTX> for SortedMap<K, V> {
+impl<K: HashStable<CTX> + StableOrd, V: HashStable<CTX>, CTX> HashStable<CTX> for SortedMap<K, V> {
     #[inline]
     fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) {
         self.data.hash_stable(ctx, hasher);
index 0ec32dc43070d23fd638a23ad6114036d4d63c2b..7af5c14942adf8c30ac0c0bc898655b97251a708 100644 (file)
@@ -1,7 +1,6 @@
 //! A variant of `SortedMap` that preserves insertion order.
 
 use std::hash::{Hash, Hasher};
-use std::iter::FromIterator;
 
 use crate::stable_hasher::{HashStable, StableHasher};
 use rustc_index::vec::{Idx, IndexVec};
@@ -120,13 +119,20 @@ fn hash<H: Hasher>(&self, hasher: &mut H) {
         self.items.hash(hasher)
     }
 }
+
 impl<I: Idx, K, V, C> HashStable<C> for SortedIndexMultiMap<I, K, V>
 where
     K: HashStable<C>,
     V: HashStable<C>,
 {
     fn hash_stable(&self, ctx: &mut C, hasher: &mut StableHasher) {
-        self.items.hash_stable(ctx, hasher)
+        let SortedIndexMultiMap {
+            items,
+            // We can ignore this field because it is not observable from the outside.
+            idx_sorted_by_item_key: _,
+        } = self;
+
+        items.hash_stable(ctx, hasher)
     }
 }
 
index 131eeef4582de6fc35df95d90470cf9881bf48e1..bca6c0955b905f8732fb72b598fc75e62d924152 100644 (file)
@@ -1,7 +1,5 @@
 use std::fmt;
-use std::iter::ExactSizeIterator;
 use std::iter::FusedIterator;
-use std::iter::Iterator;
 
 /// Iterator which may contain instance of
 /// one of two specific implementations.
index ec6a62016a87cffad47430832d96f4554d5567aa..7cdac58197714840081099415c7fadd866b76f75 100644 (file)
@@ -3,7 +3,6 @@
 use arrayvec::ArrayVec;
 use std::fmt;
 use std::hash::Hash;
-use std::iter::FromIterator;
 use std::ops::Index;
 
 // For pointer-sized arguments arrays
index 406f0270dcc1b50587a35354ad677152f7287f47..a4b40138933dedc2cf12c370df798509f1aca3f7 100644 (file)
@@ -1,6 +1,5 @@
 use std::fmt;
 use std::hash::Hash;
-use std::iter::FromIterator;
 
 use super::map::SsoHashMap;
 
index ce8591734188077a14b3d8b3c8d2db460d720217..1a728f82f006fa33a92597defccda7ac8e441431 100644 (file)
@@ -219,7 +219,35 @@ pub trait ToStableHashKey<HCX> {
     fn to_stable_hash_key(&self, hcx: &HCX) -> Self::KeyType;
 }
 
-/// Implement HashStable by just calling `Hash::hash()`.
+/// Trait for marking a type as having a sort order that is
+/// stable across compilation session boundaries. More formally:
+///
+/// ```txt
+/// Ord::cmp(a1, b1) == Ord:cmp(a2, b2)
+///    where a2 = decode(encode(a1, context1), context2)
+///          b2 = decode(encode(b1, context1), context2)
+/// ```
+///
+/// i.e. the result of `Ord::cmp` is not influenced by encoding
+/// the values in one session and then decoding them in another
+/// session.
+///
+/// This is trivially true for types where encoding and decoding
+/// don't change the bytes of the values that are used during
+/// comparison and comparison only depends on these bytes (as
+/// opposed to some non-local state). Examples are u32, String,
+/// Path, etc.
+///
+/// But it is not true for:
+///  - `*const T` and `*mut T` because the values of these pointers
+///    will change between sessions.
+///  - `DefIndex`, `CrateNum`, `LocalDefId`, because their concrete
+///    values depend on state that might be different between
+///    compilation sessions.
+pub unsafe trait StableOrd: Ord {}
+
+/// Implement HashStable by just calling `Hash::hash()`. Also implement `StableOrd` for the type since
+/// that has the same requirements.
 ///
 /// **WARNING** This is only valid for types that *really* don't need any context for fingerprinting.
 /// But it is easy to misuse this macro (see [#96013](https://github.com/rust-lang/rust/issues/96013)
@@ -227,7 +255,7 @@ pub trait ToStableHashKey<HCX> {
 /// here in this module.
 ///
 /// Use `#[derive(HashStable_Generic)]` instead.
-macro_rules! impl_stable_hash_via_hash {
+macro_rules! impl_stable_traits_for_trivial_type {
     ($t:ty) => {
         impl<CTX> $crate::stable_hasher::HashStable<CTX> for $t {
             #[inline]
@@ -235,26 +263,28 @@ fn hash_stable(&self, _: &mut CTX, hasher: &mut $crate::stable_hasher::StableHas
                 ::std::hash::Hash::hash(self, hasher);
             }
         }
+
+        unsafe impl $crate::stable_hasher::StableOrd for $t {}
     };
 }
 
-impl_stable_hash_via_hash!(i8);
-impl_stable_hash_via_hash!(i16);
-impl_stable_hash_via_hash!(i32);
-impl_stable_hash_via_hash!(i64);
-impl_stable_hash_via_hash!(isize);
+impl_stable_traits_for_trivial_type!(i8);
+impl_stable_traits_for_trivial_type!(i16);
+impl_stable_traits_for_trivial_type!(i32);
+impl_stable_traits_for_trivial_type!(i64);
+impl_stable_traits_for_trivial_type!(isize);
 
-impl_stable_hash_via_hash!(u8);
-impl_stable_hash_via_hash!(u16);
-impl_stable_hash_via_hash!(u32);
-impl_stable_hash_via_hash!(u64);
-impl_stable_hash_via_hash!(usize);
+impl_stable_traits_for_trivial_type!(u8);
+impl_stable_traits_for_trivial_type!(u16);
+impl_stable_traits_for_trivial_type!(u32);
+impl_stable_traits_for_trivial_type!(u64);
+impl_stable_traits_for_trivial_type!(usize);
 
-impl_stable_hash_via_hash!(u128);
-impl_stable_hash_via_hash!(i128);
+impl_stable_traits_for_trivial_type!(u128);
+impl_stable_traits_for_trivial_type!(i128);
 
-impl_stable_hash_via_hash!(char);
-impl_stable_hash_via_hash!(());
+impl_stable_traits_for_trivial_type!(char);
+impl_stable_traits_for_trivial_type!(());
 
 impl<CTX> HashStable<CTX> for ! {
     fn hash_stable(&self, _ctx: &mut CTX, _hasher: &mut StableHasher) {
@@ -366,7 +396,7 @@ fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) {
 impl<T: HashStable<CTX>, CTX> HashStable<CTX> for Vec<T> {
     #[inline]
     fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) {
-        (&self[..]).hash_stable(ctx, hasher);
+        self[..].hash_stable(ctx, hasher);
     }
 }
 
@@ -399,13 +429,13 @@ fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) {
     }
 }
 
-impl<A, CTX> HashStable<CTX> for SmallVec<[A; 1]>
+impl<A, const N: usize, CTX> HashStable<CTX> for SmallVec<[A; N]>
 where
     A: HashStable<CTX>,
 {
     #[inline]
     fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) {
-        (&self[..]).hash_stable(ctx, hasher);
+        self[..].hash_stable(ctx, hasher);
     }
 }
 
@@ -440,10 +470,14 @@ fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) {
 impl<CTX> HashStable<CTX> for String {
     #[inline]
     fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) {
-        (&self[..]).hash_stable(hcx, hasher);
+        self[..].hash_stable(hcx, hasher);
     }
 }
 
+// Safety: String comparison only depends on their contents and the
+// contents are not changed by (de-)serialization.
+unsafe impl StableOrd for String {}
+
 impl<HCX> ToStableHashKey<HCX> for String {
     type KeyType = String;
     #[inline]
@@ -459,6 +493,9 @@ fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) {
     }
 }
 
+// Safety: sort order of bools is not changed by (de-)serialization.
+unsafe impl StableOrd for bool {}
+
 impl<T, CTX> HashStable<CTX> for Option<T>
 where
     T: HashStable<CTX>,
@@ -474,6 +511,9 @@ fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) {
     }
 }
 
+// Safety: the Option wrapper does not add instability to comparison.
+unsafe impl<T: StableOrd> StableOrd for Option<T> {}
+
 impl<T1, T2, CTX> HashStable<CTX> for Result<T1, T2>
 where
     T1: HashStable<CTX>,
@@ -550,8 +590,8 @@ fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) {
     }
 }
 
-impl_stable_hash_via_hash!(::std::path::Path);
-impl_stable_hash_via_hash!(::std::path::PathBuf);
+impl_stable_traits_for_trivial_type!(::std::path::Path);
+impl_stable_traits_for_trivial_type!(::std::path::PathBuf);
 
 impl<K, V, R, HCX> HashStable<HCX> for ::std::collections::HashMap<K, V, R>
 where
@@ -584,27 +624,26 @@ fn hash_stable(&self, hcx: &mut HCX, hasher: &mut StableHasher) {
 
 impl<K, V, HCX> HashStable<HCX> for ::std::collections::BTreeMap<K, V>
 where
-    K: ToStableHashKey<HCX>,
+    K: HashStable<HCX> + StableOrd,
     V: HashStable<HCX>,
 {
     fn hash_stable(&self, hcx: &mut HCX, hasher: &mut StableHasher) {
-        stable_hash_reduce(hcx, hasher, self.iter(), self.len(), |hasher, hcx, (key, value)| {
-            let key = key.to_stable_hash_key(hcx);
-            key.hash_stable(hcx, hasher);
-            value.hash_stable(hcx, hasher);
-        });
+        self.len().hash_stable(hcx, hasher);
+        for entry in self.iter() {
+            entry.hash_stable(hcx, hasher);
+        }
     }
 }
 
 impl<K, HCX> HashStable<HCX> for ::std::collections::BTreeSet<K>
 where
-    K: ToStableHashKey<HCX>,
+    K: HashStable<HCX> + StableOrd,
 {
     fn hash_stable(&self, hcx: &mut HCX, hasher: &mut StableHasher) {
-        stable_hash_reduce(hcx, hasher, self.iter(), self.len(), |hasher, hcx, key| {
-            let key = key.to_stable_hash_key(hcx);
-            key.hash_stable(hcx, hasher);
-        });
+        self.len().hash_stable(hcx, hasher);
+        for entry in self.iter() {
+            entry.hash_stable(hcx, hasher);
+        }
     }
 }
 
index c550f246e094aa77358d0010610e108226caf5af..ed5341c40ef08b70ee2fae389ad86b949f80ba8b 100644 (file)
@@ -138,7 +138,7 @@ macro_rules! parallel {
             }
         }
 
-        pub use std::iter::Iterator as ParallelIterator;
+        pub use Iterator as ParallelIterator;
 
         pub fn par_iter<T: IntoIterator>(t: T) -> T::IntoIter {
             t.into_iter()
@@ -201,7 +201,7 @@ impl<T> Deref for WorkerLocal<T> {
 
             #[inline(always)]
             fn deref(&self) -> &T {
-                &*self.0
+                &self.0
             }
         }
 
index d44ccd368b3cbb507c630fca26432c7a7da39da2..b0315c93d934d7a359266dd89ddfa86268c5d4a4 100644 (file)
@@ -76,7 +76,7 @@ impl<P, T, const COMPARE_PACKED: bool> Drop for TaggedPtr<P, T, COMPARE_PACKED>
     fn drop(&mut self) {
         // No need to drop the tag, as it's Copy
         unsafe {
-            std::mem::drop(P::from_usize(self.raw.pointer_raw()));
+            drop(P::from_usize(self.raw.pointer_raw()));
         }
     }
 }
index 86be0bd8775d76cdcca9553035d3a8c973fc590c..2417df66bb9d8a2b0dd0d4ac09744a0d8dba0cdc 100644 (file)
@@ -1,6 +1,5 @@
 use std::borrow::Borrow;
 use std::fmt::Debug;
-use std::iter::FromIterator;
 use std::slice::Iter;
 use std::vec::IntoIter;
 
index 380fbd732d505ef7e784a47213520b9e0f9f9186..711eed2b2723118a11a64ceeb11f01ca651f30da 100644 (file)
@@ -25,6 +25,7 @@
 use rustc_errors::registry::{InvalidErrorCode, Registry};
 use rustc_errors::{ErrorGuaranteed, PResult};
 use rustc_feature::find_gated_cfg;
+use rustc_hir::def_id::LOCAL_CRATE;
 use rustc_interface::util::{self, collect_crate_types, get_codegen_backend};
 use rustc_interface::{interface, Queries};
 use rustc_lint::LintStore;
@@ -44,7 +45,6 @@
 
 use std::borrow::Cow;
 use std::cmp::max;
-use std::default::Default;
 use std::env;
 use std::ffi::OsString;
 use std::fs;
@@ -245,10 +245,8 @@ fn run_compiler(
                 interface::run_compiler(config, |compiler| {
                     let sopts = &compiler.session().opts;
                     if sopts.describe_lints {
-                        let mut lint_store = rustc_lint::new_lint_store(
-                            sopts.unstable_opts.no_interleave_lints,
-                            compiler.session().enable_internal_lints(),
-                        );
+                        let mut lint_store =
+                            rustc_lint::new_lint_store(compiler.session().enable_internal_lints());
                         let registered_lints =
                             if let Some(register_lints) = compiler.register_lints() {
                                 register_lints(compiler.session(), &mut lint_store);
@@ -376,14 +374,14 @@ fn run_compiler(
             queries.global_ctxt()?.peek_mut().enter(|tcx| {
                 let result = tcx.analysis(());
                 if sess.opts.unstable_opts.save_analysis {
-                    let crate_name = queries.crate_name()?.peek().clone();
+                    let crate_name = tcx.crate_name(LOCAL_CRATE);
                     sess.time("save_analysis", || {
                         save::process_crate(
                             tcx,
-                            &crate_name,
+                            crate_name,
                             compiler.input(),
                             None,
-                            DumpHandler::new(compiler.output_dir().as_deref(), &crate_name),
+                            DumpHandler::new(compiler.output_dir().as_deref(), crate_name),
                         )
                     });
                 }
@@ -680,7 +678,7 @@ fn print_crate_info(
                 let crate_types = collect_crate_types(sess, attrs);
                 for &style in &crate_types {
                     let fname =
-                        rustc_session::output::filename_for_input(sess, style, &id, &t_outputs);
+                        rustc_session::output::filename_for_input(sess, style, id, &t_outputs);
                     println!("{}", fname.file_name().unwrap().to_string_lossy());
                 }
             }
index 1e86d159668ffe5d6b1bca194df8bb1a359c6d18..31a709c36d4bc57461cf93cc57840ece6635ebc2 100644 (file)
 E0787: include_str!("./error_codes/E0787.md"),
 E0788: include_str!("./error_codes/E0788.md"),
 E0790: include_str!("./error_codes/E0790.md"),
+E0791: include_str!("./error_codes/E0791.md"),
 ;
 //  E0006, // merged with E0005
 //  E0008, // cannot bind by-move into a pattern guard
index 79e7c069a91c42cdb62d62be42c245702a32798d..7c0719dc217d06089d726acca31a965d7a99a69f 100644 (file)
@@ -55,7 +55,6 @@ wrapper:
 
 ```
 use std::cell::Cell;
-use std::marker::Sync;
 
 struct NotThreadSafe<T> {
     value: Cell<T>,
diff --git a/compiler/rustc_error_codes/src/error_codes/E0791.md b/compiler/rustc_error_codes/src/error_codes/E0791.md
new file mode 100644 (file)
index 0000000..61d2f51
--- /dev/null
@@ -0,0 +1,41 @@
+Static variables with the `#[linkage]` attribute within external blocks
+must have one of the following types, which are equivalent to a nullable
+pointer in C:
+
+* `*mut T` or `*const T`, where `T` may be any type.
+
+* An enumerator type with no `#[repr]` attribute and with two variants, where
+  one of the variants has no fields, and the other has a single field of one of
+  the following non-nullable types:
+  * Reference type
+  * Function pointer type
+
+  The variants can appear in either order.
+
+For example, the following declaration is invalid:
+
+```compile_fail,E0791
+#![feature(linkage)]
+
+extern "C" {
+    #[linkage = "extern_weak"]
+    static foo: i8;
+}
+```
+
+The following declarations are valid:
+
+```
+#![feature(linkage)]
+
+extern "C" {
+    #[linkage = "extern_weak"]
+    static foo: Option<unsafe extern "C" fn()>;
+
+    #[linkage = "extern_weak"]
+    static bar: Option<&'static i8>;
+
+    #[linkage = "extern_weak"]
+    static baz: *mut i8;
+}
+```
index 178e1a67ccecff46fb28b1bfc715ec1cd0287fbf..08ce5172574ac3bb1af28314ec2200a26b8d221a 100644 (file)
@@ -1,9 +1,3 @@
-codegen_gcc_ranlib_failure =
-    Ranlib exited with code {$exit_code}
-
-codegen_gcc_linkage_const_or_mut_type =
-    must have type `*const T` or `*mut T` due to `#[linkage]` attribute
-
 codegen_gcc_unwinding_inline_asm =
     GCC backend does not support unwinding from inline asm
 
index 68a205df6c7ad05207b41617b23b8defd7dab31c..97198cb4be2c827def75802a49b4af95bc5adaf0 100644 (file)
@@ -23,15 +23,9 @@ codegen_llvm_branch_protection_requires_aarch64 =
 codegen_llvm_invalid_minimum_alignment =
     invalid minimum global alignment: {$err}
 
-codegen_llvm_linkage_const_or_mut_type =
-    must have type `*const T` or `*mut T` due to `#[linkage]` attribute
-
 codegen_llvm_sanitizer_memtag_requires_mte =
     `-Zsanitizer=memtag` requires `-Ctarget-feature=+mte`
 
-codegen_llvm_archive_build_failure =
-    failed to build archive: {$error}
-
 codegen_llvm_error_writing_def_file =
     Error writing .DEF file: {$error}
 
@@ -41,9 +35,6 @@ codegen_llvm_error_calling_dlltool =
 codegen_llvm_dlltool_fail_import_library =
     Dlltool could not create import library: {$stdout}\n{$stderr}
 
-codegen_llvm_unknown_archive_kind =
-    Don't know how to build archive of type: {$kind}
-
 codegen_llvm_target_feature_disable_or_enable =
     the target features {$features} must all be either enabled or disabled together
 
index 70ce559526c3619dbbd9fd8592610f699c8e07db..4d1f9c1c901fc63d7fc4d877c76379baa2634e8b 100644 (file)
@@ -186,3 +186,9 @@ codegen_ssa_apple_sdk_error_sdk_path = failed to get {$sdk_name} SDK path: {erro
 codegen_ssa_read_file = failed to read file: {message}
 
 codegen_ssa_unsupported_link_self_contained = option `-C link-self-contained` is not supported on this target
+
+codegen_ssa_archive_build_failure =
+    failed to build archive: {$error}
+
+codegen_ssa_unknown_archive_kind =
+    Don't know how to build archive of type: {$kind}
index 5720591154f9914e2ff3f9ada81c45edb4252118..df0e8ae5dd8f5d11bb0577d502ef388e44d132e3 100644 (file)
@@ -20,3 +20,110 @@ expand_var_still_repeating =
     variable '{$ident}' is still repeating at this depth
 
 expand_meta_var_dif_seq_matchers = {$msg}
+
+expand_macro_const_stability =
+    macros cannot have const stability attributes
+    .label = invalid const stability attribute
+    .label2 = const stability attribute affects this macro
+
+expand_macro_body_stability =
+    macros cannot have body stability attributes
+    .label = invalid body stability attribute
+    .label2 = body stability attribute affects this macro
+
+expand_resolve_relative_path =
+    cannot resolve relative path in non-file source `{$path}`
+
+expand_attr_no_arguments =
+    attribute must have either one or two arguments
+
+expand_not_a_meta_item =
+    not a meta item
+
+expand_only_one_word =
+    must only be one word
+
+expand_cannot_be_name_of_macro =
+    `{$trait_ident}` cannot be a name of {$macro_type} macro
+
+expand_arg_not_attributes =
+    second argument must be `attributes`
+
+expand_attributes_wrong_form =
+    attribute must be of form: `attributes(foo, bar)`
+
+expand_attribute_meta_item =
+    attribute must be a meta item, not a literal
+
+expand_attribute_single_word =
+    attribute must only be a single word
+
+expand_helper_attribute_name_invalid =
+    `{$name}` cannot be a name of derive helper attribute
+
+expand_expected_comma_in_list =
+    expected token: `,`
+
+expand_only_one_argument =
+    {$name} takes 1 argument
+
+expand_takes_no_arguments =
+    {$name} takes no arguments
+
+expand_feature_included_in_edition =
+    the feature `{$feature}` is included in the Rust {$edition} edition
+
+expand_feature_removed =
+    feature has been removed
+    .label = feature has been removed
+    .reason = {$reason}
+
+expand_feature_not_allowed =
+    the feature `{$name}` is not in the list of allowed features
+
+expand_recursion_limit_reached =
+    recursion limit reached while expanding `{$descr}`
+    .help = consider increasing the recursion limit by adding a `#![recursion_limit = "{$suggested_limit}"]` attribute to your crate (`{$crate_name}`)
+
+expand_malformed_feature_attribute =
+    malformed `feature` attribute input
+    .expected = expected just one word
+
+expand_remove_expr_not_supported =
+    removing an expression is not supported in this position
+
+expand_invalid_cfg_no_parens = `cfg` is not followed by parentheses
+expand_invalid_cfg_no_predicate = `cfg` predicate is not specified
+expand_invalid_cfg_multiple_predicates = multiple `cfg` predicates are specified
+expand_invalid_cfg_predicate_literal = `cfg` predicate key cannot be a literal
+expand_invalid_cfg_expected_syntax = expected syntax is
+
+expand_wrong_fragment_kind =
+    non-{$kind} macro in {$kind} position: {$name}
+
+expand_unsupported_key_value =
+    key-value macro attributes are not supported
+
+expand_incomplete_parse =
+    macro expansion ignores token `{$token}` and any following
+    .label = caused by the macro expansion here
+    .note = the usage of `{$macro_path}!` is likely invalid in {$kind_name} context
+    .suggestion_add_semi = you might be missing a semicolon here
+
+expand_remove_node_not_supported =
+    removing {$descr} is not supported in this position
+
+expand_module_circular =
+    circular modules: {$modules}
+
+expand_module_in_block =
+    cannot declare a non-inline module inside a block unless it has a path attribute
+    .note = maybe `use` the module `{$name}` instead of redeclaring it
+
+expand_module_file_not_found =
+    file not found for module `{$name}`
+    .help = to create the module `{$name}`, create file "{$default_path}" or "{$secondary_path}"
+
+expand_module_multiple_candidates =
+    file for module `{$name}` found at both "{$default_path}" and "{$secondary_path}"
+    .help = delete or rename one of them to remove the ambiguity
index 0894bbcaad474b5b36f8712a068e188b283992c8..a9ea161b93eda2251a9c779dc1eabfad0a36baa1 100644 (file)
@@ -17,6 +17,8 @@ hir_analysis_lifetimes_or_bounds_mismatch_on_trait =
     lifetime parameters or bounds on {$item_kind} `{$ident}` do not match the trait declaration
     .label = lifetimes do not match {$item_kind} in trait
     .generics_label = lifetimes in impl do not match this {$item_kind} in trait
+    .where_label = this `where` clause might not match the one in the trait
+    .bounds_label = this bound might be missing in the impl
 
 hir_analysis_drop_impl_on_wrong_item =
     the `Drop` trait may only be implemented for local structs, enums, and unions
@@ -113,3 +115,6 @@ hir_analysis_const_bound_for_non_const_trait =
 hir_analysis_self_in_impl_self =
     `Self` is not valid in the self type of an impl block
     .note = replace `Self` with a different type
+
+hir_analysis_linkage_type =
+    invalid type for variable with `#[linkage]` attribute
index c450c276366e156220e09c14077eb72c23e4727b..d8879bf70ed39730ee41f5029b51f096b17278b2 100644 (file)
@@ -39,7 +39,7 @@ fn fluent_bundle(&self) -> Option<&Lrc<FluentBundle>> {
     }
 
     fn fallback_fluent_bundle(&self) -> &FluentBundle {
-        &**self.fallback_bundle
+        &self.fallback_bundle
     }
 }
 
@@ -49,7 +49,7 @@ fn emit_diagnostic(&mut self, diag: &Diagnostic) {
         let fluent_args = to_fluent_args(diag.args());
 
         let mut children = diag.children.clone();
-        let (mut primary_span, suggestions) = self.primary_span_formatted(&diag, &fluent_args);
+        let (mut primary_span, suggestions) = self.primary_span_formatted(diag, &fluent_args);
 
         self.fix_multispans_in_extern_macros_and_render_macro_backtrace(
             &mut primary_span,
@@ -65,7 +65,7 @@ fn emit_diagnostic(&mut self, diag: &Diagnostic) {
             &diag.code,
             &primary_span,
             &children,
-            &suggestions,
+            suggestions,
         );
     }
 
index 7d5e4723a6d883b6b22bf24c19259c93f210c3fa..06bb5edc090f48c8b6c326961982ce9730aa6957 100644 (file)
@@ -292,7 +292,7 @@ pub fn update_unstable_expectation_id(
             let lint_index = expectation_id.get_lint_index();
             expectation_id.set_lint_index(None);
             let mut stable_id = unstable_to_stable
-                .get(&expectation_id)
+                .get(expectation_id)
                 .expect("each unstable `LintExpectationId` must have a matching stable id")
                 .normalize();
 
index 7155db32e53b7f75e71c4e592c70aa58a4278362..628cb90903feedebcfe049f7cfeef978e6f053e3 100644 (file)
@@ -59,7 +59,7 @@ fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
     i128,
     u128,
     std::io::Error,
-    std::boxed::Box<dyn std::error::Error>,
+    Box<dyn std::error::Error>,
     std::num::NonZeroU32,
     hir::Target,
     Edition,
@@ -152,6 +152,12 @@ fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
     }
 }
 
+impl IntoDiagnosticArg for &ast::Path {
+    fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
+        DiagnosticArgValue::Str(Cow::Owned(pprust::path_to_string(self)))
+    }
+}
+
 impl IntoDiagnosticArg for ast::token::Token {
     fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
         DiagnosticArgValue::Str(pprust::token_to_string(&self))
index 1fabe15ff83ba4563a5618988f9242640fa67835..4df2198fb0e9bc8eaad61d0babc663efe6e6bd72 100644 (file)
@@ -24,7 +24,7 @@
 
 use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
 use rustc_data_structures::sync::Lrc;
-use rustc_error_messages::FluentArgs;
+use rustc_error_messages::{FluentArgs, SpanLabel};
 use rustc_span::hygiene::{ExpnKind, MacroKind};
 use std::borrow::Cow;
 use std::cmp::{max, min, Reverse};
@@ -283,7 +283,7 @@ fn primary_span_formatted<'a>(
                         if self
                             .source_map()
                             .map(|sm| is_case_difference(
-                                &**sm,
+                                sm,
                                 substitution,
                                 sugg.substitutions[0].parts[0].span,
                             ))
@@ -525,7 +525,7 @@ fn fluent_bundle(&self) -> Option<&Lrc<FluentBundle>> {
     }
 
     fn fallback_fluent_bundle(&self) -> &FluentBundle {
-        &**self.fallback_bundle
+        &self.fallback_bundle
     }
 }
 
@@ -538,7 +538,7 @@ fn emit_diagnostic(&mut self, diag: &Diagnostic) {
         let fluent_args = to_fluent_args(diag.args());
 
         let mut children = diag.children.clone();
-        let (mut primary_span, suggestions) = self.primary_span_formatted(&diag, &fluent_args);
+        let (mut primary_span, suggestions) = self.primary_span_formatted(diag, &fluent_args);
         debug!("emit_diagnostic: suggestions={:?}", suggestions);
 
         self.fix_multispans_in_extern_macros_and_render_macro_backtrace(
@@ -555,7 +555,7 @@ fn emit_diagnostic(&mut self, diag: &Diagnostic) {
             &diag.code,
             &primary_span,
             &children,
-            &suggestions,
+            suggestions,
             self.track_diagnostics.then_some(&diag.emitted_at),
         );
     }
@@ -773,6 +773,7 @@ fn draw_line(
         draw_col_separator_no_space(buffer, line_offset, width_offset - 2);
     }
 
+    #[instrument(level = "trace", skip(self), ret)]
     fn render_source_line(
         &self,
         buffer: &mut StyledBuffer,
@@ -801,9 +802,10 @@ fn render_source_line(
         }
 
         let source_string = match file.get_line(line.line_index - 1) {
-            Some(s) => normalize_whitespace(&*s),
+            Some(s) => normalize_whitespace(&s),
             None => return Vec::new(),
         };
+        trace!(?source_string);
 
         let line_offset = buffer.num_lines();
 
@@ -1148,7 +1150,7 @@ fn render_source_line(
                 (pos + 2, annotation.start_col.saturating_sub(left))
             };
             if let Some(ref label) = annotation.label {
-                buffer.puts(line_offset + pos, code_offset + col, &label, style);
+                buffer.puts(line_offset + pos, code_offset + col, label, style);
             }
         }
 
@@ -1323,6 +1325,7 @@ fn style_or_override(style: Style, override_: Option<Style>) -> Style {
         }
     }
 
+    #[instrument(level = "trace", skip(self, args), ret)]
     fn emit_message_default(
         &mut self,
         msp: &MultiSpan,
@@ -1358,7 +1361,7 @@ fn emit_message_default(
             // only render error codes, not lint codes
             if let Some(DiagnosticId::Error(ref code)) = *code {
                 buffer.append(0, "[", Style::Level(*level));
-                buffer.append(0, &code, Style::Level(*level));
+                buffer.append(0, code, Style::Level(*level));
                 buffer.append(0, "]", Style::Level(*level));
                 label_width += 2 + code.len();
             }
@@ -1384,22 +1387,15 @@ fn emit_message_default(
             }
         }
         let mut annotated_files = FileWithAnnotatedLines::collect_annotations(self, args, msp);
+        trace!("{annotated_files:#?}");
 
         // Make sure our primary file comes first
-        let (primary_lo, sm) = if let (Some(sm), Some(ref primary_span)) =
-            (self.sm.as_ref(), msp.primary_span().as_ref())
-        {
-            if !primary_span.is_dummy() {
-                (sm.lookup_char_pos(primary_span.lo()), sm)
-            } else {
-                emit_to_destination(&buffer.render(), level, &mut self.dst, self.short_message)?;
-                return Ok(());
-            }
-        } else {
+        let primary_span = msp.primary_span().unwrap_or_default();
+        let (Some(sm), false) = (self.sm.as_ref(), primary_span.is_dummy()) else {
             // If we don't have span information, emit and exit
-            emit_to_destination(&buffer.render(), level, &mut self.dst, self.short_message)?;
-            return Ok(());
+            return emit_to_destination(&buffer.render(), level, &mut self.dst, self.short_message);
         };
+        let primary_lo = sm.lookup_char_pos(primary_span.lo());
         if let Ok(pos) =
             annotated_files.binary_search_by(|x| x.file.name.cmp(&primary_lo.file.name))
         {
@@ -1410,6 +1406,54 @@ fn emit_message_default(
         for annotated_file in annotated_files {
             // we can't annotate anything if the source is unavailable.
             if !sm.ensure_source_file_source_present(annotated_file.file.clone()) {
+                if !self.short_message {
+                    // We'll just print an unannotated message.
+                    for (annotation_id, line) in annotated_file.lines.into_iter().enumerate() {
+                        let mut annotations = line.annotations.clone();
+                        annotations.sort_by_key(|a| Reverse(a.start_col));
+                        let mut line_idx = buffer.num_lines();
+                        buffer.append(
+                            line_idx,
+                            &format!(
+                                "{}:{}:{}",
+                                sm.filename_for_diagnostics(&annotated_file.file.name),
+                                sm.doctest_offset_line(&annotated_file.file.name, line.line_index),
+                                annotations[0].start_col + 1,
+                            ),
+                            Style::LineAndColumn,
+                        );
+                        if annotation_id == 0 {
+                            buffer.prepend(line_idx, "--> ", Style::LineNumber);
+                            for _ in 0..max_line_num_len {
+                                buffer.prepend(line_idx, " ", Style::NoStyle);
+                            }
+                            line_idx += 1;
+                        };
+                        for (i, annotation) in annotations.into_iter().enumerate() {
+                            if let Some(label) = &annotation.label {
+                                let style = if annotation.is_primary {
+                                    Style::LabelPrimary
+                                } else {
+                                    Style::LabelSecondary
+                                };
+                                if annotation_id == 0 {
+                                    buffer.prepend(line_idx, " |", Style::LineNumber);
+                                    for _ in 0..max_line_num_len {
+                                        buffer.prepend(line_idx, " ", Style::NoStyle);
+                                    }
+                                    line_idx += 1;
+                                    buffer.append(line_idx + i, " = note: ", style);
+                                    for _ in 0..max_line_num_len {
+                                        buffer.prepend(line_idx, " ", Style::NoStyle);
+                                    }
+                                } else {
+                                    buffer.append(line_idx + i, ": ", style);
+                                }
+                                buffer.append(line_idx + i, label, style);
+                            }
+                        }
+                    }
+                }
                 continue;
             }
 
@@ -1656,6 +1700,7 @@ fn emit_message_default(
                     multilines.extend(&to_add);
                 }
             }
+            trace!("buffer: {:#?}", buffer.render());
         }
 
         if let Some(tracked) = emitted_at {
@@ -1683,7 +1728,7 @@ fn emit_suggestion_default(
         };
 
         // Render the replacements for each suggestion
-        let suggestions = suggestion.splice_lines(&**sm);
+        let suggestions = suggestion.splice_lines(sm);
         debug!("emit_suggestion_default: suggestions={:?}", suggestions);
 
         if suggestions.is_empty() {
@@ -1784,7 +1829,7 @@ fn emit_suggestion_default(
                     buffer.puts(
                         row_num - 1 + line - line_start,
                         max_line_num_len + 3,
-                        &normalize_whitespace(&*file_lines.file.get_line(line - 1).unwrap()),
+                        &normalize_whitespace(&file_lines.file.get_line(line - 1).unwrap()),
                         Style::Removal,
                     );
                 }
@@ -1926,7 +1971,7 @@ fn emit_suggestion_default(
                             buffer.putc(
                                 row_num,
                                 (padding as isize + p) as usize,
-                                if part.is_addition(&sm) { '+' } else { '~' },
+                                if part.is_addition(sm) { '+' } else { '~' },
                                 Style::Addition,
                             );
                         }
@@ -1973,12 +2018,13 @@ fn emit_suggestion_default(
             buffer.puts(row_num, max_line_num_len + 3, &msg, Style::NoStyle);
         } else if notice_capitalization {
             let msg = "notice the capitalization difference";
-            buffer.puts(row_num, max_line_num_len + 3, &msg, Style::NoStyle);
+            buffer.puts(row_num, max_line_num_len + 3, msg, Style::NoStyle);
         }
         emit_to_destination(&buffer.render(), level, &mut self.dst, self.short_message)?;
         Ok(())
     }
 
+    #[instrument(level = "trace", skip(self, args, code, children, suggestions))]
     fn emit_messages_default(
         &mut self,
         level: &Level,
@@ -2028,7 +2074,7 @@ fn emit_messages_default(
                     for child in children {
                         let span = child.render_span.as_ref().unwrap_or(&child.span);
                         if let Err(err) = self.emit_message_default(
-                            &span,
+                            span,
                             &child.message,
                             args,
                             &None,
@@ -2113,7 +2159,7 @@ fn draw_code_line(
                 *row_num - 1,
                 max_line_num_len + 3,
                 &normalize_whitespace(
-                    &*file_lines.file.get_line(file_lines.lines[line_pos].line_index).unwrap(),
+                    &file_lines.file.get_line(file_lines.lines[line_pos].line_index).unwrap(),
                 ),
                 Style::NoStyle,
             );
@@ -2209,46 +2255,28 @@ fn add_annotation_to_file(
         let mut multiline_annotations = vec![];
 
         if let Some(ref sm) = emitter.source_map() {
-            for span_label in msp.span_labels() {
-                let fixup_lo_hi = |span: Span| {
-                    let lo = sm.lookup_char_pos(span.lo());
-                    let mut hi = sm.lookup_char_pos(span.hi());
-
-                    // Watch out for "empty spans". If we get a span like 6..6, we
-                    // want to just display a `^` at 6, so convert that to
-                    // 6..7. This is degenerate input, but it's best to degrade
-                    // gracefully -- and the parser likes to supply a span like
-                    // that for EOF, in particular.
-
-                    if lo.col_display == hi.col_display && lo.line == hi.line {
-                        hi.col_display += 1;
-                    }
-                    (lo, hi)
+            for SpanLabel { span, is_primary, label } in msp.span_labels() {
+                // If we don't have a useful span, pick the primary span if that exists.
+                // Worst case we'll just print an error at the top of the main file.
+                let span = match (span.is_dummy(), msp.primary_span()) {
+                    (_, None) | (false, _) => span,
+                    (true, Some(span)) => span,
                 };
 
-                if span_label.span.is_dummy() {
-                    if let Some(span) = msp.primary_span() {
-                        // if we don't know where to render the annotation, emit it as a note
-                        // on the primary span.
-
-                        let (lo, hi) = fixup_lo_hi(span);
-
-                        let ann = Annotation {
-                            start_col: lo.col_display,
-                            end_col: hi.col_display,
-                            is_primary: span_label.is_primary,
-                            label: span_label
-                                .label
-                                .as_ref()
-                                .map(|m| emitter.translate_message(m, args).to_string()),
-                            annotation_type: AnnotationType::Singleline,
-                        };
-                        add_annotation_to_file(&mut output, lo.file, lo.line, ann);
-                    }
-                    continue;
+                let lo = sm.lookup_char_pos(span.lo());
+                let mut hi = sm.lookup_char_pos(span.hi());
+
+                // Watch out for "empty spans". If we get a span like 6..6, we
+                // want to just display a `^` at 6, so convert that to
+                // 6..7. This is degenerate input, but it's best to degrade
+                // gracefully -- and the parser likes to supply a span like
+                // that for EOF, in particular.
+
+                if lo.col_display == hi.col_display && lo.line == hi.line {
+                    hi.col_display += 1;
                 }
 
-                let (lo, hi) = fixup_lo_hi(span_label.span);
+                let label = label.as_ref().map(|m| emitter.translate_message(m, args).to_string());
 
                 if lo.line != hi.line {
                     let ml = MultilineAnnotation {
@@ -2257,11 +2285,8 @@ fn add_annotation_to_file(
                         line_end: hi.line,
                         start_col: lo.col_display,
                         end_col: hi.col_display,
-                        is_primary: span_label.is_primary,
-                        label: span_label
-                            .label
-                            .as_ref()
-                            .map(|m| emitter.translate_message(m, args).to_string()),
+                        is_primary,
+                        label,
                         overlaps_exactly: false,
                     };
                     multiline_annotations.push((lo.file, ml));
@@ -2269,11 +2294,8 @@ fn add_annotation_to_file(
                     let ann = Annotation {
                         start_col: lo.col_display,
                         end_col: hi.col_display,
-                        is_primary: span_label.is_primary,
-                        label: span_label
-                            .label
-                            .as_ref()
-                            .map(|m| emitter.translate_message(m, args).to_string()),
+                        is_primary,
+                        label,
                         annotation_type: AnnotationType::Singleline,
                     };
                     add_annotation_to_file(&mut output, lo.file, lo.line, ann);
index c4498eafa4eab1f287cfe1a8699706571f865777..a37073d8fa32a5a653bdce4cc2280429e4cbb4b3 100644 (file)
@@ -136,7 +136,7 @@ fn fluent_bundle(&self) -> Option<&Lrc<FluentBundle>> {
     }
 
     fn fallback_fluent_bundle(&self) -> &FluentBundle {
-        &**self.fallback_bundle
+        &self.fallback_bundle
     }
 }
 
index 2be36a6eeb4a25c55f32174be78fb93f47a90d50..eb0506c459afa732b0bf07918bf8adfde11659af 100644 (file)
@@ -470,6 +470,7 @@ pub enum StashKey {
     /// Maybe there was a typo where a comma was forgotten before
     /// FRU syntax
     MaybeFruTypo,
+    CallAssocMethod,
 }
 
 fn default_track_diagnostic(_: &Diagnostic) {}
@@ -1328,7 +1329,7 @@ fn emit_diagnostic(&mut self, diagnostic: &mut Diagnostic) -> Option<ErrorGuaran
 
             diagnostic.children.drain_filter(already_emitted_sub).for_each(|_| {});
 
-            self.emitter.emit_diagnostic(&diagnostic);
+            self.emitter.emit_diagnostic(diagnostic);
             if diagnostic.is_error() {
                 self.deduplicated_err_count += 1;
             } else if let Warning(_) = diagnostic.level {
index a452fac074787348a0bf5666d5b7b55cfa00421f..afd660ff1bf1fb6c13d70c6a385243e8c0294f33 100644 (file)
@@ -59,13 +59,13 @@ fn translate_message<'a>(
         trace!(?message, ?args);
         let (identifier, attr) = match message {
             DiagnosticMessage::Str(msg) | DiagnosticMessage::Eager(msg) => {
-                return Cow::Borrowed(&msg);
+                return Cow::Borrowed(msg);
             }
             DiagnosticMessage::FluentIdentifier(identifier, attr) => (identifier, attr),
         };
 
         let translate_with_bundle = |bundle: &'a FluentBundle| -> Option<(Cow<'_, str>, Vec<_>)> {
-            let message = bundle.get_message(&identifier)?;
+            let message = bundle.get_message(identifier)?;
             let value = match attr {
                 Some(attr) => message.get_attribute(attr)?.value(),
                 None => message.value()?,
@@ -73,7 +73,7 @@ fn translate_message<'a>(
             debug!(?message, ?value);
 
             let mut errs = vec![];
-            let translated = bundle.format_pattern(value, Some(&args), &mut errs);
+            let translated = bundle.format_pattern(value, Some(args), &mut errs);
             debug!(?translated, ?errs);
             Some((translated, errs))
         };
index d491e9e34a78471bb612e70b6d531171d61bd3ab..00453f78287efb8ab9067dbbf1fae3a27e43984e 100644 (file)
@@ -1,3 +1,11 @@
+#![deny(rustc::untranslatable_diagnostic)]
+
+use crate::errors::{
+    ArgumentNotAttributes, AttrNoArguments, AttributeMetaItem, AttributeSingleWord,
+    AttributesWrongForm, CannotBeNameOfMacro, ExpectedCommaInList, HelperAttributeNameInvalid,
+    MacroBodyStability, MacroConstStability, NotAMetaItem, OnlyOneArgument, OnlyOneWord,
+    ResolveRelativePath, TakesNoArguments,
+};
 use crate::expand::{self, AstFragment, Invocation};
 use crate::module::DirOwnership;
 
@@ -26,7 +34,6 @@
 use rustc_span::{BytePos, FileName, RealFileName, Span, DUMMY_SP};
 use smallvec::{smallvec, SmallVec};
 
-use std::default::Default;
 use std::iter;
 use std::path::PathBuf;
 use std::rc::Rc;
@@ -789,26 +796,16 @@ pub fn new(
             .unwrap_or_else(|| (None, helper_attrs));
         let (stability, const_stability, body_stability) = attr::find_stability(&sess, attrs, span);
         if let Some((_, sp)) = const_stability {
-            sess.parse_sess
-                .span_diagnostic
-                .struct_span_err(sp, "macros cannot have const stability attributes")
-                .span_label(sp, "invalid const stability attribute")
-                .span_label(
-                    sess.source_map().guess_head_span(span),
-                    "const stability attribute affects this macro",
-                )
-                .emit();
+            sess.emit_err(MacroConstStability {
+                span: sp,
+                head_span: sess.source_map().guess_head_span(span),
+            });
         }
         if let Some((_, sp)) = body_stability {
-            sess.parse_sess
-                .span_diagnostic
-                .struct_span_err(sp, "macros cannot have body stability attributes")
-                .span_label(sp, "invalid body stability attribute")
-                .span_label(
-                    sess.source_map().guess_head_span(span),
-                    "body stability attribute affects this macro",
-                )
-                .emit();
+            sess.emit_err(MacroBodyStability {
+                span: sp,
+                head_span: sess.source_map().guess_head_span(span),
+            });
         }
 
         SyntaxExtension {
@@ -960,7 +957,7 @@ fn pre_expansion_lint(
         node_id: NodeId,
         attrs: &[Attribute],
         items: &[P<Item>],
-        name: &str,
+        name: Symbol,
     );
 }
 
@@ -1200,13 +1197,11 @@ pub fn resolve_path(
                 .expect("attempting to resolve a file path in an external file"),
             FileName::DocTest(path, _) => path,
             other => {
-                return Err(parse_sess.span_diagnostic.struct_span_err(
+                return Err(ResolveRelativePath {
                     span,
-                    &format!(
-                        "cannot resolve relative path in non-file source `{}`",
-                        parse_sess.source_map().filename_for_diagnostics(&other)
-                    ),
-                ));
+                    path: parse_sess.source_map().filename_for_diagnostics(&other).to_string(),
+                }
+                .into_diagnostic(&parse_sess.span_diagnostic));
             }
         };
         result.pop();
@@ -1222,6 +1217,8 @@ pub fn resolve_path(
 /// The returned bool indicates whether an applicable suggestion has already been
 /// added to the diagnostic to avoid emitting multiple suggestions. `Err(None)`
 /// indicates that an ast error was encountered.
+// FIXME(Nilstrieb) Make this function setup translatable
+#[allow(rustc::untranslatable_diagnostic)]
 pub fn expr_to_spanned_string<'a>(
     cx: &'a mut ExtCtxt<'_>,
     expr: P<ast::Expr>,
@@ -1280,9 +1277,9 @@ pub fn expr_to_string(
 /// compilation should call
 /// `cx.parse_sess.span_diagnostic.abort_if_errors()` (this should be
 /// done as rarely as possible).
-pub fn check_zero_tts(cx: &ExtCtxt<'_>, sp: Span, tts: TokenStream, name: &str) {
+pub fn check_zero_tts(cx: &ExtCtxt<'_>, span: Span, tts: TokenStream, name: &str) {
     if !tts.is_empty() {
-        cx.span_err(sp, &format!("{} takes no arguments", name));
+        cx.emit_err(TakesNoArguments { span, name });
     }
 }
 
@@ -1304,31 +1301,27 @@ pub fn parse_expr(p: &mut parser::Parser<'_>) -> Option<P<ast::Expr>> {
 /// expect exactly one string literal, or emit an error and return `None`.
 pub fn get_single_str_from_tts(
     cx: &mut ExtCtxt<'_>,
-    sp: Span,
+    span: Span,
     tts: TokenStream,
     name: &str,
 ) -> Option<Symbol> {
     let mut p = cx.new_parser_from_tts(tts);
     if p.token == token::Eof {
-        cx.span_err(sp, &format!("{} takes 1 argument", name));
+        cx.emit_err(OnlyOneArgument { span, name });
         return None;
     }
     let ret = parse_expr(&mut p)?;
     let _ = p.eat(&token::Comma);
 
     if p.token != token::Eof {
-        cx.span_err(sp, &format!("{} takes 1 argument", name));
+        cx.emit_err(OnlyOneArgument { span, name });
     }
     expr_to_string(cx, ret, "argument must be a string literal").map(|(s, _)| s)
 }
 
 /// Extracts comma-separated expressions from `tts`.
 /// On error, emit it, and return `None`.
-pub fn get_exprs_from_tts(
-    cx: &mut ExtCtxt<'_>,
-    sp: Span,
-    tts: TokenStream,
-) -> Option<Vec<P<ast::Expr>>> {
+pub fn get_exprs_from_tts(cx: &mut ExtCtxt<'_>, tts: TokenStream) -> Option<Vec<P<ast::Expr>>> {
     let mut p = cx.new_parser_from_tts(tts);
     let mut es = Vec::new();
     while p.token != token::Eof {
@@ -1343,7 +1336,7 @@ pub fn get_exprs_from_tts(
             continue;
         }
         if p.token != token::Eof {
-            cx.span_err(sp, "expected token: `,`");
+            cx.emit_err(ExpectedCommaInList { span: p.token.span });
             return None;
         }
     }
@@ -1353,64 +1346,58 @@ pub fn get_exprs_from_tts(
 pub fn parse_macro_name_and_helper_attrs(
     diag: &rustc_errors::Handler,
     attr: &Attribute,
-    descr: &str,
+    macro_type: &str,
 ) -> Option<(Symbol, Vec<Symbol>)> {
     // Once we've located the `#[proc_macro_derive]` attribute, verify
     // that it's of the form `#[proc_macro_derive(Foo)]` or
     // `#[proc_macro_derive(Foo, attributes(A, ..))]`
     let list = attr.meta_item_list()?;
     if list.len() != 1 && list.len() != 2 {
-        diag.span_err(attr.span, "attribute must have either one or two arguments");
+        diag.emit_err(AttrNoArguments { span: attr.span });
         return None;
     }
     let Some(trait_attr) = list[0].meta_item() else {
-        diag.span_err(list[0].span(), "not a meta item");
+        diag.emit_err(NotAMetaItem {span: list[0].span()});
         return None;
     };
     let trait_ident = match trait_attr.ident() {
         Some(trait_ident) if trait_attr.is_word() => trait_ident,
         _ => {
-            diag.span_err(trait_attr.span, "must only be one word");
+            diag.emit_err(OnlyOneWord { span: trait_attr.span });
             return None;
         }
     };
 
     if !trait_ident.name.can_be_raw() {
-        diag.span_err(
-            trait_attr.span,
-            &format!("`{}` cannot be a name of {} macro", trait_ident, descr),
-        );
+        diag.emit_err(CannotBeNameOfMacro { span: trait_attr.span, trait_ident, macro_type });
     }
 
     let attributes_attr = list.get(1);
     let proc_attrs: Vec<_> = if let Some(attr) = attributes_attr {
         if !attr.has_name(sym::attributes) {
-            diag.span_err(attr.span(), "second argument must be `attributes`");
+            diag.emit_err(ArgumentNotAttributes { span: attr.span() });
         }
         attr.meta_item_list()
             .unwrap_or_else(|| {
-                diag.span_err(attr.span(), "attribute must be of form: `attributes(foo, bar)`");
+                diag.emit_err(AttributesWrongForm { span: attr.span() });
                 &[]
             })
             .iter()
             .filter_map(|attr| {
                 let Some(attr) = attr.meta_item() else {
-                    diag.span_err(attr.span(), "not a meta item");
+                    diag.emit_err(AttributeMetaItem { span: attr.span() });
                     return None;
                 };
 
                 let ident = match attr.ident() {
                     Some(ident) if attr.is_word() => ident,
                     _ => {
-                        diag.span_err(attr.span, "must only be one word");
+                        diag.emit_err(AttributeSingleWord { span: attr.span });
                         return None;
                     }
                 };
                 if !ident.name.can_be_raw() {
-                    diag.span_err(
-                        attr.span,
-                        &format!("`{}` cannot be a name of derive helper attribute", ident),
-                    );
+                    diag.emit_err(HelperAttributeNameInvalid { span: attr.span, name: ident });
                 }
 
                 Some(ident.name)
index 2fec24a1aece8c9262a4953215a5b228f3cce405..ef50efb81253fccd1c224c92f9a61e7d34b9471c 100644 (file)
@@ -538,6 +538,9 @@ pub fn lambda(&self, span: Span, ids: Vec<Ident>, body: P<ast::Expr>) -> P<ast::
                 fn_decl,
                 body,
                 fn_decl_span: span,
+                // FIXME(SarthakSingh31): This points to the start of the declaration block and
+                // not the span of the argument block.
+                fn_arg_span: span,
             })),
         )
     }
index 2510795c2e3ed5073c6aa07a2331b06c87f02e17..f4c6f3386ade23ce244e629ce715ce72a37d83e7 100644 (file)
@@ -1,5 +1,9 @@
 //! Conditional compilation stripping.
 
+use crate::errors::{
+    FeatureIncludedInEdition, FeatureNotAllowed, FeatureRemoved, FeatureRemovedReason, InvalidCfg,
+    MalformedFeatureAttribute, MalformedFeatureAttributeHelp, RemoveExprNotSupported,
+};
 use rustc_ast::ptr::P;
 use rustc_ast::token::{Delimiter, Token, TokenKind};
 use rustc_ast::tokenstream::{AttrTokenStream, AttrTokenTree};
@@ -10,7 +14,6 @@
 use rustc_attr as attr;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::map_in_place::MapInPlace;
-use rustc_errors::{error_code, struct_span_err, Applicability, Handler};
 use rustc_feature::{Feature, Features, State as FeatureState};
 use rustc_feature::{
     ACCEPTED_FEATURES, ACTIVE_FEATURES, REMOVED_FEATURES, STABLE_REMOVED_FEATURES,
@@ -33,18 +36,12 @@ pub struct StripUnconfigured<'a> {
     pub lint_node_id: NodeId,
 }
 
-fn get_features(
-    sess: &Session,
-    span_handler: &Handler,
-    krate_attrs: &[ast::Attribute],
-) -> Features {
-    fn feature_removed(span_handler: &Handler, span: Span, reason: Option<&str>) {
-        let mut err = struct_span_err!(span_handler, span, E0557, "feature has been removed");
-        err.span_label(span, "feature has been removed");
-        if let Some(reason) = reason {
-            err.note(reason);
-        }
-        err.emit();
+fn get_features(sess: &Session, krate_attrs: &[ast::Attribute]) -> Features {
+    fn feature_removed(sess: &Session, span: Span, reason: Option<&str>) {
+        sess.emit_err(FeatureRemoved {
+            span,
+            reason: reason.map(|reason| FeatureRemovedReason { reason }),
+        });
     }
 
     fn active_features_up_to(edition: Edition) -> impl Iterator<Item = &'static Feature> {
@@ -117,34 +114,34 @@ fn active_features_up_to(edition: Edition) -> impl Iterator<Item = &'static Feat
             continue;
         };
 
-        let bad_input = |span| {
-            struct_span_err!(span_handler, span, E0556, "malformed `feature` attribute input")
-        };
-
         for mi in list {
             let name = match mi.ident() {
                 Some(ident) if mi.is_word() => ident.name,
                 Some(ident) => {
-                    bad_input(mi.span())
-                        .span_suggestion(
-                            mi.span(),
-                            "expected just one word",
-                            ident.name,
-                            Applicability::MaybeIncorrect,
-                        )
-                        .emit();
+                    sess.emit_err(MalformedFeatureAttribute {
+                        span: mi.span(),
+                        help: MalformedFeatureAttributeHelp::Suggestion {
+                            span: mi.span(),
+                            suggestion: ident.name,
+                        },
+                    });
                     continue;
                 }
                 None => {
-                    bad_input(mi.span()).span_label(mi.span(), "expected just one word").emit();
+                    sess.emit_err(MalformedFeatureAttribute {
+                        span: mi.span(),
+                        help: MalformedFeatureAttributeHelp::Label { span: mi.span() },
+                    });
                     continue;
                 }
             };
 
-            if let Some(edition) = edition_enabled_features.get(&name) {
-                let msg =
-                    &format!("the feature `{}` is included in the Rust {} edition", name, edition);
-                span_handler.struct_span_warn_with_code(mi.span(), msg, error_code!(E0705)).emit();
+            if let Some(&edition) = edition_enabled_features.get(&name) {
+                sess.emit_warning(FeatureIncludedInEdition {
+                    span: mi.span(),
+                    feature: name,
+                    edition,
+                });
                 continue;
             }
 
@@ -159,7 +156,7 @@ fn active_features_up_to(edition: Edition) -> impl Iterator<Item = &'static Feat
                 if let FeatureState::Removed { reason } | FeatureState::Stabilized { reason } =
                     state
                 {
-                    feature_removed(span_handler, mi.span(), *reason);
+                    feature_removed(sess, mi.span(), *reason);
                     continue;
                 }
             }
@@ -173,14 +170,7 @@ fn active_features_up_to(edition: Edition) -> impl Iterator<Item = &'static Feat
 
             if let Some(allowed) = sess.opts.unstable_opts.allow_features.as_ref() {
                 if allowed.iter().all(|f| name.as_str() != f) {
-                    struct_span_err!(
-                        span_handler,
-                        mi.span(),
-                        E0725,
-                        "the feature `{}` is not in the list of allowed features",
-                        name
-                    )
-                    .emit();
+                    sess.emit_err(FeatureNotAllowed { span: mi.span(), name });
                     continue;
                 }
             }
@@ -221,7 +211,7 @@ pub fn features(
         }
         Some(attrs) => {
             krate.attrs = attrs;
-            let features = get_features(sess, diag, &krate.attrs);
+            let features = get_features(sess, &krate.attrs);
             if err_count == diag.err_count() {
                 // Avoid reconfiguring malformed `cfg_attr`s.
                 strip_unconfigured.features = Some(&features);
@@ -503,8 +493,7 @@ pub fn configure_expr(&self, expr: &mut P<ast::Expr>, method_receiver: bool) {
         // N.B., this is intentionally not part of the visit_expr() function
         //     in order for filter_map_expr() to be able to avoid this check
         if let Some(attr) = expr.attrs().iter().find(|a| is_cfg(*a)) {
-            let msg = "removing an expression is not supported in this position";
-            self.sess.parse_sess.span_diagnostic.span_err(attr.span, msg);
+            self.sess.emit_err(RemoveExprNotSupported { span: attr.span });
         }
 
         self.process_cfg_attrs(expr);
@@ -513,27 +502,26 @@ pub fn configure_expr(&self, expr: &mut P<ast::Expr>, method_receiver: bool) {
 }
 
 pub fn parse_cfg<'a>(meta_item: &'a MetaItem, sess: &Session) -> Option<&'a MetaItem> {
-    let error = |span, msg, suggestion: &str| {
-        let mut err = sess.parse_sess.span_diagnostic.struct_span_err(span, msg);
-        if !suggestion.is_empty() {
-            err.span_suggestion(
-                span,
-                "expected syntax is",
-                suggestion,
-                Applicability::HasPlaceholders,
-            );
-        }
-        err.emit();
-        None
-    };
     let span = meta_item.span;
     match meta_item.meta_item_list() {
-        None => error(span, "`cfg` is not followed by parentheses", "cfg(/* predicate */)"),
-        Some([]) => error(span, "`cfg` predicate is not specified", ""),
-        Some([_, .., l]) => error(l.span(), "multiple `cfg` predicates are specified", ""),
+        None => {
+            sess.emit_err(InvalidCfg::NotFollowedByParens { span });
+            None
+        }
+        Some([]) => {
+            sess.emit_err(InvalidCfg::NoPredicate { span });
+            None
+        }
+        Some([_, .., l]) => {
+            sess.emit_err(InvalidCfg::MultiplePredicates { span: l.span() });
+            None
+        }
         Some([single]) => match single.meta_item() {
             Some(meta_item) => Some(meta_item),
-            None => error(single.span(), "`cfg` predicate key cannot be a literal", ""),
+            None => {
+                sess.emit_err(InvalidCfg::PredicateLiteral { span: single.span() });
+                None
+            }
         },
     }
 }
index d383f4832f6999469ed43a96dbddd7d7a532b3a7..afe5169d3f5c0b616754ddf8ac7fa80ebd12b894 100644 (file)
@@ -1,6 +1,10 @@
+use rustc_ast::ast;
 use rustc_macros::Diagnostic;
-use rustc_span::symbol::MacroRulesNormalizedIdent;
-use rustc_span::Span;
+use rustc_session::Limit;
+use rustc_span::edition::Edition;
+use rustc_span::symbol::{Ident, MacroRulesNormalizedIdent};
+use rustc_span::{Span, Symbol};
+use std::borrow::Cow;
 
 #[derive(Diagnostic)]
 #[diag(expand_expr_repeat_no_syntax_vars)]
@@ -46,3 +50,321 @@ pub(crate) struct MetaVarsDifSeqMatchers {
     pub span: Span,
     pub msg: String,
 }
+
+#[derive(Diagnostic)]
+#[diag(expand_resolve_relative_path)]
+pub(crate) struct ResolveRelativePath {
+    #[primary_span]
+    pub span: Span,
+    pub path: String,
+}
+
+#[derive(Diagnostic)]
+#[diag(expand_macro_const_stability)]
+pub(crate) struct MacroConstStability {
+    #[primary_span]
+    #[label]
+    pub span: Span,
+    #[label(label2)]
+    pub head_span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(expand_macro_body_stability)]
+pub(crate) struct MacroBodyStability {
+    #[primary_span]
+    #[label]
+    pub span: Span,
+    #[label(label2)]
+    pub head_span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(expand_attr_no_arguments)]
+pub(crate) struct AttrNoArguments {
+    #[primary_span]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(expand_not_a_meta_item)]
+pub(crate) struct NotAMetaItem {
+    #[primary_span]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(expand_only_one_word)]
+pub(crate) struct OnlyOneWord {
+    #[primary_span]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(expand_cannot_be_name_of_macro)]
+pub(crate) struct CannotBeNameOfMacro<'a> {
+    #[primary_span]
+    pub span: Span,
+    pub trait_ident: Ident,
+    pub macro_type: &'a str,
+}
+
+#[derive(Diagnostic)]
+#[diag(expand_arg_not_attributes)]
+pub(crate) struct ArgumentNotAttributes {
+    #[primary_span]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(expand_attributes_wrong_form)]
+pub(crate) struct AttributesWrongForm {
+    #[primary_span]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(expand_attribute_meta_item)]
+pub(crate) struct AttributeMetaItem {
+    #[primary_span]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(expand_attribute_single_word)]
+pub(crate) struct AttributeSingleWord {
+    #[primary_span]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(expand_helper_attribute_name_invalid)]
+pub(crate) struct HelperAttributeNameInvalid {
+    #[primary_span]
+    pub span: Span,
+    pub name: Ident,
+}
+
+#[derive(Diagnostic)]
+#[diag(expand_expected_comma_in_list)]
+pub(crate) struct ExpectedCommaInList {
+    #[primary_span]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(expand_only_one_argument)]
+pub(crate) struct OnlyOneArgument<'a> {
+    #[primary_span]
+    pub span: Span,
+    pub name: &'a str,
+}
+
+#[derive(Diagnostic)]
+#[diag(expand_takes_no_arguments)]
+pub(crate) struct TakesNoArguments<'a> {
+    #[primary_span]
+    pub span: Span,
+    pub name: &'a str,
+}
+
+#[derive(Diagnostic)]
+#[diag(expand_feature_included_in_edition, code = "E0705")]
+pub(crate) struct FeatureIncludedInEdition {
+    #[primary_span]
+    pub span: Span,
+    pub feature: Symbol,
+    pub edition: Edition,
+}
+
+#[derive(Diagnostic)]
+#[diag(expand_feature_removed, code = "E0557")]
+pub(crate) struct FeatureRemoved<'a> {
+    #[primary_span]
+    #[label]
+    pub span: Span,
+    #[subdiagnostic]
+    pub reason: Option<FeatureRemovedReason<'a>>,
+}
+
+#[derive(Subdiagnostic)]
+#[note(reason)]
+pub(crate) struct FeatureRemovedReason<'a> {
+    pub reason: &'a str,
+}
+
+#[derive(Diagnostic)]
+#[diag(expand_feature_not_allowed, code = "E0725")]
+pub(crate) struct FeatureNotAllowed {
+    #[primary_span]
+    pub span: Span,
+    pub name: Symbol,
+}
+
+#[derive(Diagnostic)]
+#[diag(expand_recursion_limit_reached)]
+#[help]
+pub(crate) struct RecursionLimitReached<'a> {
+    #[primary_span]
+    pub span: Span,
+    pub descr: String,
+    pub suggested_limit: Limit,
+    pub crate_name: &'a str,
+}
+
+#[derive(Diagnostic)]
+#[diag(expand_malformed_feature_attribute, code = "E0556")]
+pub(crate) struct MalformedFeatureAttribute {
+    #[primary_span]
+    pub span: Span,
+    #[subdiagnostic]
+    pub help: MalformedFeatureAttributeHelp,
+}
+
+#[derive(Subdiagnostic)]
+pub(crate) enum MalformedFeatureAttributeHelp {
+    #[label(expected)]
+    Label {
+        #[primary_span]
+        span: Span,
+    },
+    #[suggestion(expected, code = "{suggestion}", applicability = "maybe-incorrect")]
+    Suggestion {
+        #[primary_span]
+        span: Span,
+        suggestion: Symbol,
+    },
+}
+
+#[derive(Diagnostic)]
+#[diag(expand_remove_expr_not_supported)]
+pub(crate) struct RemoveExprNotSupported {
+    #[primary_span]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
+pub(crate) enum InvalidCfg {
+    #[diag(expand_invalid_cfg_no_parens)]
+    NotFollowedByParens {
+        #[primary_span]
+        #[suggestion(
+            expand_invalid_cfg_expected_syntax,
+            code = "cfg(/* predicate */)",
+            applicability = "has-placeholders"
+        )]
+        span: Span,
+    },
+    #[diag(expand_invalid_cfg_no_predicate)]
+    NoPredicate {
+        #[primary_span]
+        #[suggestion(
+            expand_invalid_cfg_expected_syntax,
+            code = "cfg(/* predicate */)",
+            applicability = "has-placeholders"
+        )]
+        span: Span,
+    },
+    #[diag(expand_invalid_cfg_multiple_predicates)]
+    MultiplePredicates {
+        #[primary_span]
+        span: Span,
+    },
+    #[diag(expand_invalid_cfg_predicate_literal)]
+    PredicateLiteral {
+        #[primary_span]
+        span: Span,
+    },
+}
+
+#[derive(Diagnostic)]
+#[diag(expand_wrong_fragment_kind)]
+pub(crate) struct WrongFragmentKind<'a> {
+    #[primary_span]
+    pub span: Span,
+    pub kind: &'a str,
+    pub name: &'a ast::Path,
+}
+
+#[derive(Diagnostic)]
+#[diag(expand_unsupported_key_value)]
+pub(crate) struct UnsupportedKeyValue {
+    #[primary_span]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(expand_incomplete_parse)]
+#[note]
+pub(crate) struct IncompleteParse<'a> {
+    #[primary_span]
+    pub span: Span,
+    pub token: Cow<'a, str>,
+    #[label]
+    pub label_span: Span,
+    pub macro_path: &'a ast::Path,
+    pub kind_name: &'a str,
+
+    #[suggestion(
+        suggestion_add_semi,
+        style = "verbose",
+        code = ";",
+        applicability = "maybe-incorrect"
+    )]
+    pub add_semicolon: Option<Span>,
+}
+
+#[derive(Diagnostic)]
+#[diag(expand_remove_node_not_supported)]
+pub(crate) struct RemoveNodeNotSupported {
+    #[primary_span]
+    pub span: Span,
+    pub descr: &'static str,
+}
+
+#[derive(Diagnostic)]
+#[diag(expand_module_circular)]
+pub(crate) struct ModuleCircular {
+    #[primary_span]
+    pub span: Span,
+    pub modules: String,
+}
+
+#[derive(Diagnostic)]
+#[diag(expand_module_in_block)]
+pub(crate) struct ModuleInBlock {
+    #[primary_span]
+    pub span: Span,
+    #[subdiagnostic]
+    pub name: Option<ModuleInBlockName>,
+}
+
+#[derive(Subdiagnostic)]
+#[note(note)]
+pub(crate) struct ModuleInBlockName {
+    #[primary_span]
+    pub span: Span,
+    pub name: Ident,
+}
+
+#[derive(Diagnostic)]
+#[diag(expand_module_file_not_found, code = "E0583")]
+#[help]
+pub(crate) struct ModuleFileNotFound {
+    #[primary_span]
+    pub span: Span,
+    pub name: Ident,
+    pub default_path: String,
+    pub secondary_path: String,
+}
+
+#[derive(Diagnostic)]
+#[diag(expand_module_multiple_candidates, code = "E0761")]
+#[help]
+pub(crate) struct ModuleMultipleCandidates {
+    #[primary_span]
+    pub span: Span,
+    pub name: Ident,
+    pub default_path: String,
+    pub secondary_path: String,
+}
index e799fa404f6fd127465d6e5c0bf8d571e55e745b..e26c16dcd7ee7784e4597cddbb6f073c9ea56657 100644 (file)
@@ -1,5 +1,9 @@
 use crate::base::*;
 use crate::config::StripUnconfigured;
+use crate::errors::{
+    IncompleteParse, RecursionLimitReached, RemoveExprNotSupported, RemoveNodeNotSupported,
+    UnsupportedKeyValue, WrongFragmentKind,
+};
 use crate::hygiene::SyntaxContext;
 use crate::mbe::diagnostics::annotate_err_with_kind;
 use crate::module::{mod_dir_path, parse_external_mod, DirOwnership, ParsedExternalMod};
@@ -18,7 +22,7 @@
 use rustc_ast_pretty::pprust;
 use rustc_data_structures::map_in_place::MapInPlace;
 use rustc_data_structures::sync::Lrc;
-use rustc_errors::{Applicability, PResult};
+use rustc_errors::PResult;
 use rustc_feature::Features;
 use rustc_parse::parser::{
     AttemptLocalParseRecovery, CommaRecoveryMode, ForceCollect, Parser, RecoverColon, RecoverComma,
@@ -606,29 +610,22 @@ fn error_recursion_limit_reached(&mut self) {
             Limit(0) => Limit(2),
             limit => limit * 2,
         };
-        self.cx
-            .struct_span_err(
-                expn_data.call_site,
-                &format!("recursion limit reached while expanding `{}`", expn_data.kind.descr()),
-            )
-            .help(&format!(
-                "consider increasing the recursion limit by adding a \
-                 `#![recursion_limit = \"{}\"]` attribute to your crate (`{}`)",
-                suggested_limit, self.cx.ecfg.crate_name,
-            ))
-            .emit();
+
+        self.cx.emit_err(RecursionLimitReached {
+            span: expn_data.call_site,
+            descr: expn_data.kind.descr(),
+            suggested_limit,
+            crate_name: &self.cx.ecfg.crate_name,
+        });
+
         self.cx.trace_macros_diag();
     }
 
     /// A macro's expansion does not fit in this fragment kind.
     /// For example, a non-type macro in a type position.
     fn error_wrong_fragment_kind(&mut self, kind: AstFragmentKind, mac: &ast::MacCall, span: Span) {
-        let msg = format!(
-            "non-{kind} macro in {kind} position: {path}",
-            kind = kind.name(),
-            path = pprust::path_to_string(&mac.path),
-        );
-        self.cx.span_err(span, &msg);
+        self.cx.emit_err(WrongFragmentKind { span, kind: kind.name(), name: &mac.path });
+
         self.cx.trace_macros_diag();
     }
 
@@ -707,7 +704,7 @@ fn expand_invoc(
                     };
                     let attr_item = attr.unwrap_normal_item();
                     if let AttrArgs::Eq(..) = attr_item.args {
-                        self.cx.span_err(span, "key-value macro attributes are not supported");
+                        self.cx.emit_err(UnsupportedKeyValue { span });
                     }
                     let inner_tokens = attr_item.args.inner_tokens();
                     let Ok(tok_result) = expander.expand(self.cx, span, inner_tokens, tokens) else {
@@ -729,9 +726,7 @@ fn expand_invoc(
                                 }
                             };
                             if fragment_kind == AstFragmentKind::Expr && items.is_empty() {
-                                let msg =
-                                    "removing an expression is not supported in this position";
-                                self.cx.span_err(span, msg);
+                                self.cx.emit_err(RemoveExprNotSupported { span });
                                 fragment_kind.dummy(span)
                             } else {
                                 fragment_kind.expect_from_annotatables(items)
@@ -939,38 +934,32 @@ pub fn parse_ast_fragment<'a>(
 }
 
 pub fn ensure_complete_parse<'a>(
-    this: &mut Parser<'a>,
+    parser: &mut Parser<'a>,
     macro_path: &ast::Path,
     kind_name: &str,
     span: Span,
 ) {
-    if this.token != token::Eof {
-        let token = pprust::token_to_string(&this.token);
-        let msg = format!("macro expansion ignores token `{}` and any following", token);
+    if parser.token != token::Eof {
+        let token = pprust::token_to_string(&parser.token);
         // Avoid emitting backtrace info twice.
-        let def_site_span = this.token.span.with_ctxt(SyntaxContext::root());
-        let mut err = this.struct_span_err(def_site_span, &msg);
-        err.span_label(span, "caused by the macro expansion here");
-        let msg = format!(
-            "the usage of `{}!` is likely invalid in {} context",
-            pprust::path_to_string(macro_path),
-            kind_name,
-        );
-        err.note(&msg);
+        let def_site_span = parser.token.span.with_ctxt(SyntaxContext::root());
 
-        let semi_span = this.sess.source_map().next_point(span);
-        match this.sess.source_map().span_to_snippet(semi_span) {
+        let semi_span = parser.sess.source_map().next_point(span);
+        let add_semicolon = match parser.sess.source_map().span_to_snippet(semi_span) {
             Ok(ref snippet) if &snippet[..] != ";" && kind_name == "expression" => {
-                err.span_suggestion(
-                    span.shrink_to_hi(),
-                    "you might be missing a semicolon here",
-                    ";",
-                    Applicability::MaybeIncorrect,
-                );
+                Some(span.shrink_to_hi())
             }
-            _ => {}
-        }
-        err.emit();
+            _ => None,
+        };
+
+        parser.sess.emit_err(IncompleteParse {
+            span: def_site_span,
+            token,
+            label_span: span,
+            macro_path,
+            kind_name,
+            add_semicolon,
+        });
     }
 }
 
@@ -1122,7 +1111,7 @@ fn wrap_flat_map_node_noop_flat_map(
                         ecx.current_expansion.lint_node_id,
                         &attrs,
                         &items,
-                        ident.name.as_str(),
+                        ident.name,
                     );
                 }
 
@@ -1766,9 +1755,8 @@ fn visit_node<Node: InvocationCollectorNode<OutputTy = Node> + DummyAstNode>(
                         if self.expand_cfg_true(node, attr, pos) {
                             continue;
                         }
-                        let msg =
-                            format!("removing {} is not supported in this position", Node::descr());
-                        self.cx.span_err(span, &msg);
+
+                        self.cx.emit_err(RemoveNodeNotSupported { span, descr: Node::descr() });
                         continue;
                     }
                     sym::cfg_attr => {
index b34de94fb7db4a43579cf08200ccf1b0399d012b..897268566358a5b0fae9d68c08e4c6655a3e57b5 100644 (file)
@@ -10,6 +10,7 @@
 #![feature(rustc_attrs)]
 #![feature(try_blocks)]
 #![recursion_limit = "256"]
+#![deny(rustc::untranslatable_diagnostic)]
 
 #[macro_use]
 extern crate rustc_macros;
 pub mod errors;
 pub mod expand;
 pub mod module;
+
+// FIXME(Nilstrieb) Translate proc_macro diagnostics
+#[allow(rustc::untranslatable_diagnostic)]
 pub mod proc_macro;
 
+// FIXME(Nilstrieb) Translate macro_rules diagnostics
+#[allow(rustc::untranslatable_diagnostic)]
 pub(crate) mod mbe;
 
 // HACK(Centril, #64197): These shouldn't really be here.
index 9002a24e42f9df671dc913fe744306dd480909ef..07f47a9c3a4f2c80f9097d22e55b2581440f5135 100644 (file)
@@ -1,13 +1,17 @@
 use crate::base::ModuleData;
+use crate::errors::{
+    ModuleCircular, ModuleFileNotFound, ModuleInBlock, ModuleInBlockName, ModuleMultipleCandidates,
+};
 use rustc_ast::ptr::P;
 use rustc_ast::{token, AttrVec, Attribute, Inline, Item, ModSpans};
-use rustc_errors::{struct_span_err, DiagnosticBuilder, ErrorGuaranteed};
+use rustc_errors::{DiagnosticBuilder, ErrorGuaranteed};
 use rustc_parse::new_parser_from_file;
 use rustc_parse::validate_attr;
 use rustc_session::parse::ParseSess;
 use rustc_session::Session;
 use rustc_span::symbol::{sym, Ident};
 use rustc_span::Span;
+use std::iter::once;
 
 use std::path::{self, Path, PathBuf};
 
@@ -242,57 +246,41 @@ pub fn default_submod_path<'a>(
 
 impl ModError<'_> {
     fn report(self, sess: &Session, span: Span) -> ErrorGuaranteed {
-        let diag = &sess.parse_sess.span_diagnostic;
         match self {
             ModError::CircularInclusion(file_paths) => {
-                let mut msg = String::from("circular modules: ");
-                for file_path in &file_paths {
-                    msg.push_str(&file_path.display().to_string());
-                    msg.push_str(" -> ");
-                }
-                msg.push_str(&file_paths[0].display().to_string());
-                diag.struct_span_err(span, &msg)
-            }
-            ModError::ModInBlock(ident) => {
-                let msg = "cannot declare a non-inline module inside a block unless it has a path attribute";
-                let mut err = diag.struct_span_err(span, msg);
-                if let Some(ident) = ident {
-                    let note =
-                        format!("maybe `use` the module `{}` instead of redeclaring it", ident);
-                    err.span_note(span, &note);
-                }
-                err
+                let path_to_string = |path: &PathBuf| path.display().to_string();
+
+                let paths = file_paths
+                    .iter()
+                    .map(path_to_string)
+                    .chain(once(path_to_string(&file_paths[0])))
+                    .collect::<Vec<_>>();
+
+                let modules = paths.join(" -> ");
+
+                sess.emit_err(ModuleCircular { span, modules })
             }
-            ModError::FileNotFound(ident, default_path, secondary_path) => {
-                let mut err = struct_span_err!(
-                    diag,
+            ModError::ModInBlock(ident) => sess.emit_err(ModuleInBlock {
+                span,
+                name: ident.map(|name| ModuleInBlockName { span, name }),
+            }),
+            ModError::FileNotFound(name, default_path, secondary_path) => {
+                sess.emit_err(ModuleFileNotFound {
                     span,
-                    E0583,
-                    "file not found for module `{}`",
-                    ident,
-                );
-                err.help(&format!(
-                    "to create the module `{}`, create file \"{}\" or \"{}\"",
-                    ident,
-                    default_path.display(),
-                    secondary_path.display(),
-                ));
-                err
+                    name,
+                    default_path: default_path.display().to_string(),
+                    secondary_path: secondary_path.display().to_string(),
+                })
             }
-            ModError::MultipleCandidates(ident, default_path, secondary_path) => {
-                let mut err = struct_span_err!(
-                    diag,
+            ModError::MultipleCandidates(name, default_path, secondary_path) => {
+                sess.emit_err(ModuleMultipleCandidates {
                     span,
-                    E0761,
-                    "file for module `{}` found at both \"{}\" and \"{}\"",
-                    ident,
-                    default_path.display(),
-                    secondary_path.display(),
-                );
-                err.help("delete or rename one of them to remove the ambiguity");
-                err
+                    name,
+                    default_path: default_path.display().to_string(),
+                    secondary_path: secondary_path.display().to_string(),
+                })
             }
-            ModError::ParserError(err) => err,
-        }.emit()
+            ModError::ParserError(mut err) => err.emit(),
+        }
     }
 }
index 539b04535a0d028f8f45f2cbabfe8828e97802ce..8f3bea29ffd2897ee30178c82969f485fcb9c8b3 100644 (file)
@@ -154,6 +154,7 @@ fn test_harness(file_text: &str, span_labels: Vec<SpanLabel>, expected_output: &
             false,
         );
         let handler = Handler::with_emitter(true, None, Box::new(emitter));
+        #[allow(rustc::untranslatable_diagnostic)]
         handler.span_err(msp, "foo");
 
         assert!(
index 4b6e068db4312505c647c66023a49332d133cd57..6d8e78a0f185dc6a16c577b6bb2a6c386f51389a 100644 (file)
@@ -394,7 +394,7 @@ pub struct BuiltinAttribute {
     ungated!(instruction_set, Normal, template!(List: "set"), ErrorPreceding),
     gated!(
         no_sanitize, Normal,
-        template!(List: "address, memory, thread"), DuplicatesOk,
+        template!(List: "address, kcfi, memory, thread"), DuplicatesOk,
         experimental!(no_sanitize)
     ),
     gated!(no_coverage, Normal, template!(Word), WarnFollowing, experimental!(no_coverage)),
index 63998bb6b00cf8467305edaad139b7d9d9fd80de..a7dfce3b9b8fce1ed528e61df14fc8cad1a2a699 100644 (file)
@@ -65,7 +65,7 @@ pub enum LinkOrCopy {
 pub fn link_or_copy<P: AsRef<Path>, Q: AsRef<Path>>(p: P, q: Q) -> io::Result<LinkOrCopy> {
     let p = p.as_ref();
     let q = q.as_ref();
-    match fs::remove_file(&q) {
+    match fs::remove_file(q) {
         Ok(()) => (),
         Err(err) if err.kind() == io::ErrorKind::NotFound => (),
         Err(err) => return Err(err),
index 401d3f6689c99e7ae4cb072a0c5d35032396e0f1..1f8268cc17c539b813021c21f1f1c88fd2689bdc 100644 (file)
@@ -410,7 +410,7 @@ pub fn new<Name: Into<Cow<'a, str>>>(name: Name) -> Result<Id<'a>, ()> {
     }
 
     pub fn as_slice(&'a self) -> &'a str {
-        &*self.name
+        &self.name
     }
 }
 
@@ -515,7 +515,7 @@ fn escape_str(s: &str) -> String {
     pub fn to_dot_string(&self) -> String {
         match *self {
             LabelStr(ref s) => format!("\"{}\"", s.escape_default()),
-            EscStr(ref s) => format!("\"{}\"", LabelText::escape_str(&s)),
+            EscStr(ref s) => format!("\"{}\"", LabelText::escape_str(s)),
             HtmlStr(ref s) => format!("<{}>", s),
         }
     }
@@ -529,7 +529,7 @@ fn pre_escaped_content(self) -> Cow<'a, str> {
             EscStr(s) => s,
             LabelStr(s) => {
                 if s.contains('\\') {
-                    (&*s).escape_default().to_string().into()
+                    s.escape_default().to_string().into()
                 } else {
                     s
                 }
index 44335b7f42ef92b3d080baa7478da566149e0eaa..c89e7eb75f8f0d9480aa31e51435eabbb9ad6947 100644 (file)
@@ -39,6 +39,7 @@ macro_rules! arena_types {
             [] param: rustc_hir::Param<'tcx>,
             [] pat: rustc_hir::Pat<'tcx>,
             [] path: rustc_hir::Path<'tcx>,
+            [] use_path: rustc_hir::UsePath<'tcx>,
             [] path_segment: rustc_hir::PathSegment<'tcx>,
             [] poly_trait_ref: rustc_hir::PolyTraitRef<'tcx>,
             [] qpath: rustc_hir::QPath<'tcx>,
index 81aedcce87728db7fcca82e1661330a22530e8ff..8bc022e1e178e19b50698104254dad839b950461 100644 (file)
@@ -183,14 +183,17 @@ pub fn is_static(&self) -> bool {
 /// `std::cmp::PartialEq`. It's represented as a sequence of identifiers,
 /// along with a bunch of supporting information.
 #[derive(Debug, HashStable_Generic)]
-pub struct Path<'hir> {
+pub struct Path<'hir, R = Res> {
     pub span: Span,
     /// The resolution for the path.
-    pub res: Res,
+    pub res: R,
     /// The segments in the path: the things separated by `::`.
     pub segments: &'hir [PathSegment<'hir>],
 }
 
+/// Up to three resolutions for type, value and macro namespaces.
+pub type UsePath<'hir> = Path<'hir, SmallVec<[Res; 3]>>;
+
 impl Path<'_> {
     pub fn is_global(&self) -> bool {
         !self.segments.is_empty() && self.segments[0].ident.name == kw::PathRoot
@@ -824,7 +827,7 @@ pub fn get(&self, id: ItemLocalId) -> &'tcx [Attribute] {
 pub struct OwnerNodes<'tcx> {
     /// Pre-computed hash of the full HIR.
     pub hash_including_bodies: Fingerprint,
-    /// Pre-computed hash of the item signature, sithout recursing into the body.
+    /// Pre-computed hash of the item signature, without recursing into the body.
     pub hash_without_bodies: Fingerprint,
     /// Full HIR for the current owner.
     // The zeroth node's parent should never be accessed: the owner's parent is computed by the
@@ -940,7 +943,10 @@ pub struct Closure<'hir> {
     pub bound_generic_params: &'hir [GenericParam<'hir>],
     pub fn_decl: &'hir FnDecl<'hir>,
     pub body: BodyId,
+    /// The span of the declaration block: 'move |...| -> ...'
     pub fn_decl_span: Span,
+    /// The span of the argument block `|...|`
+    pub fn_arg_span: Option<Span>,
     pub movability: Option<Movability>,
 }
 
@@ -2431,7 +2437,7 @@ pub fn as_generic_param(&self) -> Option<(DefId, Ident)> {
     pub fn peel_refs(&self) -> &Self {
         let mut final_ty = self;
         while let TyKind::Rptr(_, MutTy { ty, .. }) = &final_ty.kind {
-            final_ty = &ty;
+            final_ty = ty;
         }
         final_ty
     }
@@ -3068,7 +3074,7 @@ pub enum ItemKind<'hir> {
     /// or just
     ///
     /// `use foo::bar::baz;` (with `as baz` implicitly on the right).
-    Use(&'hir Path<'hir>, UseKind),
+    Use(&'hir UsePath<'hir>, UseKind),
 
     /// A `static` item.
     Static(&'hir Ty<'hir>, Mutability, BodyId),
index 33f02a115ef38639019453ff23630ed239863ef3..060f40919f5c8d16fd4490d5aab593aa5b4e8452 100644 (file)
@@ -1,5 +1,5 @@
 use crate::def_id::{DefId, DefIndex, LocalDefId, CRATE_DEF_ID};
-use rustc_data_structures::stable_hasher::{HashStable, StableHasher, ToStableHashKey};
+use rustc_data_structures::stable_hasher::{HashStable, StableHasher, StableOrd, ToStableHashKey};
 use rustc_span::{def_id::DefPathHash, HashStableContext};
 use std::fmt;
 
@@ -116,7 +116,7 @@ fn cmp(&self, other: &Self) -> std::cmp::Ordering {
 
 impl PartialOrd for HirId {
     fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
-        Some(self.cmp(&other))
+        Some(self.cmp(other))
     }
 }
 
@@ -146,6 +146,10 @@ impl ItemLocalId {
     pub const INVALID: ItemLocalId = ItemLocalId::MAX;
 }
 
+// Safety: Ord is implement as just comparing the LocalItemId's numerical
+// values and these are not changed by (de-)serialization.
+unsafe impl StableOrd for ItemLocalId {}
+
 /// The `HirId` corresponding to `CRATE_NODE_ID` and `CRATE_DEF_ID`.
 pub const CRATE_HIR_ID: HirId =
     HirId { owner: OwnerId { def_id: CRATE_DEF_ID }, local_id: ItemLocalId::from_u32(0) };
index 957f8c1058e9869a63561a8c0b776f50ac42facb..938ace2c785bbf1aa7d2bd9cfd50a5bf98146979 100644 (file)
@@ -367,7 +367,7 @@ fn visit_fn_decl(&mut self, fd: &'v FnDecl<'v>) {
     fn visit_fn(&mut self, fk: FnKind<'v>, fd: &'v FnDecl<'v>, b: BodyId, _: Span, id: HirId) {
         walk_fn(self, fk, fd, b, id)
     }
-    fn visit_use(&mut self, path: &'v Path<'v>, hir_id: HirId) {
+    fn visit_use(&mut self, path: &'v UsePath<'v>, hir_id: HirId) {
         walk_use(self, path, hir_id)
     }
     fn visit_trait_item(&mut self, ti: &'v TraitItem<'v>) {
@@ -422,7 +422,7 @@ fn visit_lifetime(&mut self, lifetime: &'v Lifetime) {
     fn visit_qpath(&mut self, qpath: &'v QPath<'v>, id: HirId, _span: Span) {
         walk_qpath(self, qpath, id)
     }
-    fn visit_path(&mut self, path: &'v Path<'v>, _id: HirId) {
+    fn visit_path(&mut self, path: &Path<'v>, _id: HirId) {
         walk_path(self, path)
     }
     fn visit_path_segment(&mut self, path_segment: &'v PathSegment<'v>) {
@@ -448,7 +448,7 @@ fn visit_inline_asm(&mut self, asm: &'v InlineAsm<'v>, id: HirId) {
 
 pub fn walk_param<'v, V: Visitor<'v>>(visitor: &mut V, param: &'v Param<'v>) {
     visitor.visit_id(param.hir_id);
-    visitor.visit_pat(&param.pat);
+    visitor.visit_pat(param.pat);
 }
 
 pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item<'v>) {
@@ -470,7 +470,7 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item<'v>) {
         }
         ItemKind::Fn(ref sig, ref generics, body_id) => visitor.visit_fn(
             FnKind::ItemFn(item.ident, generics, sig.header),
-            &sig.decl,
+            sig.decl,
             body_id,
             item.span,
             item.hir_id(),
@@ -544,7 +544,7 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item<'v>) {
 
 pub fn walk_body<'v, V: Visitor<'v>>(visitor: &mut V, body: &'v Body<'v>) {
     walk_list!(visitor, visit_param, body.params);
-    visitor.visit_expr(&body.value);
+    visitor.visit_expr(body.value);
 }
 
 pub fn walk_ident<'v, V: Visitor<'v>>(visitor: &mut V, ident: Ident) {
@@ -580,7 +580,7 @@ pub fn walk_local<'v, V: Visitor<'v>>(visitor: &mut V, local: &'v Local<'v>) {
     // dominates the local's definition.
     walk_list!(visitor, visit_expr, &local.init);
     visitor.visit_id(local.hir_id);
-    visitor.visit_pat(&local.pat);
+    visitor.visit_pat(local.pat);
     if let Some(els) = local.els {
         visitor.visit_block(els);
     }
@@ -606,7 +606,7 @@ pub fn walk_stmt<'v, V: Visitor<'v>>(visitor: &mut V, statement: &'v Stmt<'v>) {
 
 pub fn walk_arm<'v, V: Visitor<'v>>(visitor: &mut V, arm: &'v Arm<'v>) {
     visitor.visit_id(arm.hir_id);
-    visitor.visit_pat(&arm.pat);
+    visitor.visit_pat(arm.pat);
     if let Some(ref g) = arm.guard {
         match g {
             Guard::If(ref e) => visitor.visit_expr(e),
@@ -615,7 +615,7 @@ pub fn walk_arm<'v, V: Visitor<'v>>(visitor: &mut V, arm: &'v Arm<'v>) {
             }
         }
     }
-    visitor.visit_expr(&arm.body);
+    visitor.visit_expr(arm.body);
 }
 
 pub fn walk_pat<'v, V: Visitor<'v>>(visitor: &mut V, pattern: &'v Pat<'v>) {
@@ -660,7 +660,7 @@ pub fn walk_pat<'v, V: Visitor<'v>>(visitor: &mut V, pattern: &'v Pat<'v>) {
 pub fn walk_pat_field<'v, V: Visitor<'v>>(visitor: &mut V, field: &'v PatField<'v>) {
     visitor.visit_id(field.hir_id);
     visitor.visit_ident(field.ident);
-    visitor.visit_pat(&field.pat)
+    visitor.visit_pat(field.pat)
 }
 
 pub fn walk_array_len<'v, V: Visitor<'v>>(visitor: &mut V, len: &'v ArrayLen) {
@@ -740,6 +740,7 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr<'v>)
             body,
             capture_clause: _,
             fn_decl_span: _,
+            fn_arg_span: _,
             movability: _,
         }) => {
             walk_list!(visitor, visit_generic_param, bound_generic_params);
@@ -799,7 +800,7 @@ pub fn walk_let_expr<'v, V: Visitor<'v>>(visitor: &mut V, let_expr: &'v Let<'v>)
 pub fn walk_expr_field<'v, V: Visitor<'v>>(visitor: &mut V, field: &'v ExprField<'v>) {
     visitor.visit_id(field.hir_id);
     visitor.visit_ident(field.ident);
-    visitor.visit_expr(&field.expr)
+    visitor.visit_expr(field.expr)
 }
 
 pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty<'v>) {
@@ -807,10 +808,10 @@ pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty<'v>) {
 
     match typ.kind {
         TyKind::Slice(ref ty) => visitor.visit_ty(ty),
-        TyKind::Ptr(ref mutable_type) => visitor.visit_ty(&mutable_type.ty),
+        TyKind::Ptr(ref mutable_type) => visitor.visit_ty(mutable_type.ty),
         TyKind::Rptr(ref lifetime, ref mutable_type) => {
             visitor.visit_lifetime(lifetime);
-            visitor.visit_ty(&mutable_type.ty)
+            visitor.visit_ty(mutable_type.ty)
         }
         TyKind::Never => {}
         TyKind::Tup(tuple_element_types) => {
@@ -818,7 +819,7 @@ pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty<'v>) {
         }
         TyKind::BareFn(ref function_declaration) => {
             walk_list!(visitor, visit_generic_param, function_declaration.generic_params);
-            visitor.visit_fn_decl(&function_declaration.decl);
+            visitor.visit_fn_decl(function_declaration.decl);
         }
         TyKind::Path(ref qpath) => {
             visitor.visit_qpath(qpath, typ.hir_id, typ.span);
@@ -938,9 +939,12 @@ pub fn walk_fn_kind<'v, V: Visitor<'v>>(visitor: &mut V, function_kind: FnKind<'
     }
 }
 
-pub fn walk_use<'v, V: Visitor<'v>>(visitor: &mut V, path: &'v Path<'v>, hir_id: HirId) {
+pub fn walk_use<'v, V: Visitor<'v>>(visitor: &mut V, path: &'v UsePath<'v>, hir_id: HirId) {
     visitor.visit_id(hir_id);
-    visitor.visit_path(path, hir_id);
+    let UsePath { segments, ref res, span } = *path;
+    for &res in res {
+        visitor.visit_path(&Path { segments, res, span }, hir_id);
+    }
 }
 
 pub fn walk_trait_item<'v, V: Visitor<'v>>(visitor: &mut V, trait_item: &'v TraitItem<'v>) {
@@ -948,8 +952,8 @@ pub fn walk_trait_item<'v, V: Visitor<'v>>(visitor: &mut V, trait_item: &'v Trai
     let TraitItem { ident, generics, ref defaultness, ref kind, span, owner_id: _ } = *trait_item;
     let hir_id = trait_item.hir_id();
     visitor.visit_ident(ident);
-    visitor.visit_generics(&generics);
-    visitor.visit_defaultness(&defaultness);
+    visitor.visit_generics(generics);
+    visitor.visit_defaultness(defaultness);
     match *kind {
         TraitItemKind::Const(ref ty, default) => {
             visitor.visit_id(hir_id);
@@ -958,13 +962,13 @@ pub fn walk_trait_item<'v, V: Visitor<'v>>(visitor: &mut V, trait_item: &'v Trai
         }
         TraitItemKind::Fn(ref sig, TraitFn::Required(param_names)) => {
             visitor.visit_id(hir_id);
-            visitor.visit_fn_decl(&sig.decl);
+            visitor.visit_fn_decl(sig.decl);
             for &param_name in param_names {
                 visitor.visit_ident(param_name);
             }
         }
         TraitItemKind::Fn(ref sig, TraitFn::Provided(body_id)) => {
-            visitor.visit_fn(FnKind::Method(ident, sig), &sig.decl, body_id, span, hir_id);
+            visitor.visit_fn(FnKind::Method(ident, sig), sig.decl, body_id, span, hir_id);
         }
         TraitItemKind::Type(bounds, ref default) => {
             visitor.visit_id(hir_id);
@@ -1006,7 +1010,7 @@ pub fn walk_impl_item<'v, V: Visitor<'v>>(visitor: &mut V, impl_item: &'v ImplIt
         ImplItemKind::Fn(ref sig, body_id) => {
             visitor.visit_fn(
                 FnKind::Method(impl_item.ident, sig),
-                &sig.decl,
+                sig.decl,
                 body_id,
                 impl_item.span,
                 impl_item.hir_id(),
@@ -1039,7 +1043,7 @@ pub fn walk_impl_item_ref<'v, V: Visitor<'v>>(visitor: &mut V, impl_item_ref: &'
 
 pub fn walk_trait_ref<'v, V: Visitor<'v>>(visitor: &mut V, trait_ref: &'v TraitRef<'v>) {
     visitor.visit_id(trait_ref.hir_ref_id);
-    visitor.visit_path(&trait_ref.path, trait_ref.hir_ref_id)
+    visitor.visit_path(trait_ref.path, trait_ref.hir_ref_id)
 }
 
 pub fn walk_param_bound<'v, V: Visitor<'v>>(visitor: &mut V, bound: &'v GenericBound<'v>) {
@@ -1071,7 +1075,7 @@ pub fn walk_struct_def<'v, V: Visitor<'v>>(
 pub fn walk_field_def<'v, V: Visitor<'v>>(visitor: &mut V, field: &'v FieldDef<'v>) {
     visitor.visit_id(field.hir_id);
     visitor.visit_ident(field.ident);
-    visitor.visit_ty(&field.ty);
+    visitor.visit_ty(field.ty);
 }
 
 pub fn walk_enum_def<'v, V: Visitor<'v>>(
@@ -1126,7 +1130,7 @@ pub fn walk_qpath<'v, V: Visitor<'v>>(visitor: &mut V, qpath: &'v QPath<'v>, id:
     }
 }
 
-pub fn walk_path<'v, V: Visitor<'v>>(visitor: &mut V, path: &'v Path<'v>) {
+pub fn walk_path<'v, V: Visitor<'v>>(visitor: &mut V, path: &Path<'v>) {
     for segment in path.segments {
         visitor.visit_path_segment(segment);
     }
index 038509031b180a3cd42417a23846ff36c00ea7c0..b51257df713ea37a273bc14fc579d3ac38eb7e9f 100644 (file)
@@ -286,10 +286,9 @@ pub fn extract(attrs: &[ast::Attribute]) -> Option<(Symbol, Span)> {
 
     // FIXME(swatinem): the following lang items are used for async lowering and
     // should become obsolete eventually.
-    ResumeTy,                sym::ResumeTy,            resume_ty,                  Target::Struct,         GenericRequirement::None;
     IdentityFuture,          sym::identity_future,     identity_future_fn,         Target::Fn,             GenericRequirement::None;
-    GetContext,              sym::get_context,         get_context_fn,             Target::Fn,             GenericRequirement::None;
 
+    Context,                 sym::Context,             context,                    Target::Struct,         GenericRequirement::None;
     FuturePoll,              sym::poll,                future_poll_fn,             Target::Method(MethodKind::Trait { body: false }), GenericRequirement::None;
 
     FromFrom,                sym::from,                from_fn,                    Target::Method(MethodKind::Trait { body: false }), GenericRequirement::None;
index 6e2fbf96cbfb3f26aabf1eb23901dffc687d68d8..e870aa543d0b5ce9737ae0deb2b0ae7de088714e 100644 (file)
@@ -6,7 +6,7 @@
 use rustc_span::symbol::Ident;
 use rustc_span::Span;
 
-use std::iter::{Enumerate, ExactSizeIterator};
+use std::iter::Enumerate;
 
 pub struct EnumerateAndAdjust<I> {
     enumerate: Enumerate<I>,
index 4636d515249d9809ed55b2fe182ef3a2c63e7ab8..d4791150947fb1fa3fa9f7a529ee113f59fea059 100644 (file)
@@ -1,5 +1,7 @@
 use crate::definitions::{DefKey, DefPathData, DisambiguatedDefPathData};
 use rustc_span::def_id::{DefPathHash, StableCrateId};
+use rustc_span::edition::Edition;
+use rustc_span::{create_session_if_not_set_then, Symbol};
 
 #[test]
 fn def_path_hash_depends_on_crate_id() {
@@ -11,26 +13,28 @@ fn def_path_hash_depends_on_crate_id() {
     // the crate by changing the crate disambiguator (e.g. via bumping the
     // crate's version number).
 
-    let id0 = StableCrateId::new("foo", false, vec!["1".to_string()]);
-    let id1 = StableCrateId::new("foo", false, vec!["2".to_string()]);
+    create_session_if_not_set_then(Edition::Edition2024, |_| {
+        let id0 = StableCrateId::new(Symbol::intern("foo"), false, vec!["1".to_string()]);
+        let id1 = StableCrateId::new(Symbol::intern("foo"), false, vec!["2".to_string()]);
 
-    let h0 = mk_test_hash(id0);
-    let h1 = mk_test_hash(id1);
+        let h0 = mk_test_hash(id0);
+        let h1 = mk_test_hash(id1);
 
-    assert_ne!(h0.stable_crate_id(), h1.stable_crate_id());
-    assert_ne!(h0.local_hash(), h1.local_hash());
+        assert_ne!(h0.stable_crate_id(), h1.stable_crate_id());
+        assert_ne!(h0.local_hash(), h1.local_hash());
 
-    fn mk_test_hash(stable_crate_id: StableCrateId) -> DefPathHash {
-        let parent_hash = DefPathHash::new(stable_crate_id, 0);
+        fn mk_test_hash(stable_crate_id: StableCrateId) -> DefPathHash {
+            let parent_hash = DefPathHash::new(stable_crate_id, 0);
 
-        let key = DefKey {
-            parent: None,
-            disambiguated_data: DisambiguatedDefPathData {
-                data: DefPathData::CrateRoot,
-                disambiguator: 0,
-            },
-        };
+            let key = DefKey {
+                parent: None,
+                disambiguated_data: DisambiguatedDefPathData {
+                    data: DefPathData::CrateRoot,
+                    disambiguator: 0,
+                },
+            };
 
-        key.compute_stable_hash(parent_hash)
-    }
+            key.compute_stable_hash(parent_hash)
+        }
+    })
 }
index 47915b4bd4e6ce6ff6e3948d59d42e2e34709b01..f64d65cc6ad7a303ac18eeca030d70b0f93c6a70 100644 (file)
@@ -11,7 +11,6 @@
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::def_id::DefId;
 use rustc_hir::GenericArg;
-use rustc_infer::infer::TyCtxtInferExt;
 use rustc_middle::ty::{
     self, subst, subst::SubstsRef, GenericParamDef, GenericParamDefKind, IsSuggestable, Ty, TyCtxt,
 };
@@ -83,9 +82,7 @@ fn generic_arg_mismatch_err(
                 Res::Def(DefKind::TyParam, src_def_id) => {
                     if let Some(param_local_id) = param.def_id.as_local() {
                         let param_name = tcx.hir().ty_param_name(param_local_id);
-                        let infcx = tcx.infer_ctxt().build();
-                        let param_type =
-                            infcx.resolve_numeric_literals_with_default(tcx.type_of(param.def_id));
+                        let param_type = tcx.type_of(param.def_id);
                         if param_type.is_suggestable(tcx, false) {
                             err.span_suggestion(
                                 tcx.def_span(src_def_id),
index 82150310638270c4c69e74d917099c2d666c9e4e..66906b331da2ece663b3b06fb9883a144b5d474a 100644 (file)
@@ -347,7 +347,7 @@ fn create_substs_for_ast_path<'a>(
                 assert!(self_ty.is_some());
             }
         } else {
-            assert!(self_ty.is_none() && parent_substs.is_empty());
+            assert!(self_ty.is_none());
         }
 
         let arg_count = Self::check_generic_arg_count(
@@ -1821,7 +1821,7 @@ pub fn associated_path_to_ty(
 
         // Check if we have an enum variant.
         let mut variant_resolution = None;
-        if let ty::Adt(adt_def, _) = qself_ty.kind() {
+        if let ty::Adt(adt_def, adt_substs) = qself_ty.kind() {
             if adt_def.is_enum() {
                 let variant_def = adt_def
                     .variants()
@@ -1923,8 +1923,14 @@ pub fn associated_path_to_ty(
                 let Some(assoc_ty_did) = self.lookup_assoc_ty(assoc_ident, hir_ref_id, span, impl_) else {
                     continue;
                 };
-                // FIXME(inherent_associated_types): This does not substitute parameters.
-                let ty = tcx.type_of(assoc_ty_did);
+                let item_substs = self.create_substs_for_associated_item(
+                    span,
+                    assoc_ty_did,
+                    assoc_segment,
+                    adt_substs,
+                );
+                let ty = tcx.bound_type_of(assoc_ty_did).subst(tcx, item_substs);
+                let ty = self.normalize_ty(span, ty);
                 return Ok((ty, DefKind::AssocTy, assoc_ty_did));
             }
         }
index 069b405423c46b16aa023d60acb5be0419dcba7a..fc0ca62090d19c62b3a1656963ef85f026d1b793 100644 (file)
@@ -1,4 +1,5 @@
 use crate::check::intrinsicck::InlineAsmCtxt;
+use crate::errors::LinkageType;
 
 use super::compare_method::check_type_bounds;
 use super::compare_method::{compare_impl_method, compare_ty_impl};
@@ -20,7 +21,7 @@
 use rustc_middle::ty::layout::{LayoutError, MAX_SIMD_LANES};
 use rustc_middle::ty::subst::GenericArgKind;
 use rustc_middle::ty::util::{Discr, IntTypeExt};
-use rustc_middle::ty::{self, ParamEnv, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable};
+use rustc_middle::ty::{self, AdtDef, ParamEnv, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable};
 use rustc_session::lint::builtin::{UNINHABITED_STATIC, UNSUPPORTED_CALLING_CONVENTIONS};
 use rustc_span::symbol::sym;
 use rustc_span::{self, Span};
@@ -478,6 +479,36 @@ fn check_opaque_meets_bounds<'tcx>(
     let _ = infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types();
 }
 
+fn is_enum_of_nonnullable_ptr<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    adt_def: AdtDef<'tcx>,
+    substs: SubstsRef<'tcx>,
+) -> bool {
+    if adt_def.repr().inhibit_enum_layout_opt() {
+        return false;
+    }
+
+    let [var_one, var_two] = &adt_def.variants().raw[..] else {
+        return false;
+    };
+    let (([], [field]) | ([field], [])) = (&var_one.fields[..], &var_two.fields[..]) else {
+        return false;
+    };
+    matches!(field.ty(tcx, substs).kind(), ty::FnPtr(..) | ty::Ref(..))
+}
+
+fn check_static_linkage<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) {
+    if tcx.codegen_fn_attrs(def_id).import_linkage.is_some() {
+        if match tcx.type_of(def_id).kind() {
+            ty::RawPtr(_) => false,
+            ty::Adt(adt_def, substs) => !is_enum_of_nonnullable_ptr(tcx, *adt_def, *substs),
+            _ => true,
+        } {
+            tcx.sess.emit_err(LinkageType { span: tcx.def_span(def_id) });
+        }
+    }
+}
+
 fn check_item_type<'tcx>(tcx: TyCtxt<'tcx>, id: hir::ItemId) {
     debug!(
         "check_item_type(it.def_id={:?}, it.name={})",
@@ -490,6 +521,7 @@ fn check_item_type<'tcx>(tcx: TyCtxt<'tcx>, id: hir::ItemId) {
             tcx.ensure().typeck(id.owner_id.def_id);
             maybe_check_static_with_link_section(tcx, id.owner_id.def_id);
             check_static_inhabited(tcx, id.owner_id.def_id);
+            check_static_linkage(tcx, id.owner_id.def_id);
         }
         DefKind::Const => {
             tcx.ensure().typeck(id.owner_id.def_id);
@@ -627,6 +659,7 @@ fn check_item_type<'tcx>(tcx: TyCtxt<'tcx>, id: hir::ItemId) {
                         }
                         hir::ForeignItemKind::Static(..) => {
                             check_static_inhabited(tcx, def_id);
+                            check_static_linkage(tcx, def_id);
                         }
                         _ => {}
                     }
index ba58672e7595a57e84872bec799a5ac88fe77d24..1d6f9b29176518a30f487dca7eab58e0610b3ccf 100644 (file)
@@ -173,13 +173,11 @@ fn compare_predicate_entailment<'tcx>(
         impl_to_placeholder_substs.rebase_onto(tcx, impl_m.container_id(tcx), trait_to_impl_substs);
     debug!("compare_impl_method: trait_to_placeholder_substs={:?}", trait_to_placeholder_substs);
 
-    let impl_m_generics = tcx.generics_of(impl_m.def_id);
-    let trait_m_generics = tcx.generics_of(trait_m.def_id);
     let impl_m_predicates = tcx.predicates_of(impl_m.def_id);
     let trait_m_predicates = tcx.predicates_of(trait_m.def_id);
 
     // Check region bounds.
-    check_region_bounds_on_impl_item(tcx, impl_m, trait_m, &trait_m_generics, &impl_m_generics)?;
+    check_region_bounds_on_impl_item(tcx, impl_m, trait_m, false)?;
 
     // Create obligations for each predicate declared by the impl
     // definition in the context of the trait's parameter
@@ -338,6 +336,7 @@ pub fn collect_trait_impl_trait_tys<'tcx>(
     // First, check a few of the same thing as `compare_impl_method`, just so we don't ICE during substitutions later.
     compare_number_of_generics(tcx, impl_m, trait_m, tcx.hir().span_if_local(impl_m.def_id), true)?;
     compare_generic_param_kinds(tcx, impl_m, trait_m, true)?;
+    check_region_bounds_on_impl_item(tcx, impl_m, trait_m, true)?;
 
     let trait_to_impl_substs = impl_trait_ref.substs;
 
@@ -722,12 +721,14 @@ fn check_region_bounds_on_impl_item<'tcx>(
     tcx: TyCtxt<'tcx>,
     impl_m: &ty::AssocItem,
     trait_m: &ty::AssocItem,
-    trait_generics: &ty::Generics,
-    impl_generics: &ty::Generics,
+    delay: bool,
 ) -> Result<(), ErrorGuaranteed> {
-    let trait_params = trait_generics.own_counts().lifetimes;
+    let impl_generics = tcx.generics_of(impl_m.def_id);
     let impl_params = impl_generics.own_counts().lifetimes;
 
+    let trait_generics = tcx.generics_of(trait_m.def_id);
+    let trait_params = trait_generics.own_counts().lifetimes;
+
     debug!(
         "check_region_bounds_on_impl_item: \
             trait_generics={:?} \
@@ -750,23 +751,56 @@ fn check_region_bounds_on_impl_item<'tcx>(
             .get_generics(impl_m.def_id.expect_local())
             .expect("expected impl item to have generics or else we can't compare them")
             .span;
-        let generics_span = if let Some(local_def_id) = trait_m.def_id.as_local() {
-            Some(
-                tcx.hir()
-                    .get_generics(local_def_id)
-                    .expect("expected trait item to have generics or else we can't compare them")
-                    .span,
-            )
-        } else {
-            None
-        };
 
-        let reported = tcx.sess.emit_err(LifetimesOrBoundsMismatchOnTrait {
-            span,
-            item_kind: assoc_item_kind_str(impl_m),
-            ident: impl_m.ident(tcx),
-            generics_span,
-        });
+        let mut generics_span = None;
+        let mut bounds_span = vec![];
+        let mut where_span = None;
+        if let Some(trait_node) = tcx.hir().get_if_local(trait_m.def_id)
+            && let Some(trait_generics) = trait_node.generics()
+        {
+            generics_span = Some(trait_generics.span);
+            // FIXME: we could potentially look at the impl's bounds to not point at bounds that
+            // *are* present in the impl.
+            for p in trait_generics.predicates {
+                if let hir::WherePredicate::BoundPredicate(pred) = p {
+                    for b in pred.bounds {
+                        if let hir::GenericBound::Outlives(lt) = b {
+                            bounds_span.push(lt.ident.span);
+                        }
+                    }
+                }
+            }
+            if let Some(impl_node) = tcx.hir().get_if_local(impl_m.def_id)
+                && let Some(impl_generics) = impl_node.generics()
+            {
+                let mut impl_bounds = 0;
+                for p in impl_generics.predicates {
+                    if let hir::WherePredicate::BoundPredicate(pred) = p {
+                        for b in pred.bounds {
+                            if let hir::GenericBound::Outlives(_) = b {
+                                impl_bounds += 1;
+                            }
+                        }
+                    }
+                }
+                if impl_bounds == bounds_span.len() {
+                    bounds_span = vec![];
+                } else if impl_generics.has_where_clause_predicates {
+                    where_span = Some(impl_generics.where_clause_span);
+                }
+            }
+        }
+        let reported = tcx
+            .sess
+            .create_err(LifetimesOrBoundsMismatchOnTrait {
+                span,
+                item_kind: assoc_item_kind_str(impl_m),
+                ident: impl_m.ident(tcx),
+                generics_span,
+                bounds_span,
+                where_span,
+            })
+            .emit_unless(delay);
         return Err(reported);
     }
 
@@ -1504,18 +1538,10 @@ fn compare_type_predicate_entailment<'tcx>(
     let trait_to_impl_substs =
         impl_substs.rebase_onto(tcx, impl_ty.container_id(tcx), impl_trait_ref.substs);
 
-    let impl_ty_generics = tcx.generics_of(impl_ty.def_id);
-    let trait_ty_generics = tcx.generics_of(trait_ty.def_id);
     let impl_ty_predicates = tcx.predicates_of(impl_ty.def_id);
     let trait_ty_predicates = tcx.predicates_of(trait_ty.def_id);
 
-    check_region_bounds_on_impl_item(
-        tcx,
-        impl_ty,
-        trait_ty,
-        &trait_ty_generics,
-        &impl_ty_generics,
-    )?;
+    check_region_bounds_on_impl_item(tcx, impl_ty, trait_ty, false)?;
 
     let impl_ty_own_bounds = impl_ty_predicates.instantiate_own(tcx, impl_substs);
 
index ff32329e431b699eccdd4b7c393a0b9de36de9e5..b315ebad4686c37d4bac86575a991a744e2c27f0 100644 (file)
@@ -241,17 +241,46 @@ fn resolve_expr<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, expr: &'tcx h
             // scopes, meaning that temporaries cannot outlive them.
             // This ensures fixed size stacks.
             hir::ExprKind::Binary(
-                source_map::Spanned { node: hir::BinOpKind::And, .. },
-                _,
-                ref r,
-            )
-            | hir::ExprKind::Binary(
-                source_map::Spanned { node: hir::BinOpKind::Or, .. },
-                _,
+                source_map::Spanned { node: hir::BinOpKind::And | hir::BinOpKind::Or, .. },
+                ref l,
                 ref r,
             ) => {
-                // For shortcircuiting operators, mark the RHS as a terminating
-                // scope since it only executes conditionally.
+                // expr is a short circuiting operator (|| or &&). As its
+                // functionality can't be overridden by traits, it always
+                // processes bool sub-expressions. bools are Copy and thus we
+                // can drop any temporaries in evaluation (read) order
+                // (with the exception of potentially failing let expressions).
+                // We achieve this by enclosing the operands in a terminating
+                // scope, both the LHS and the RHS.
+
+                // We optimize this a little in the presence of chains.
+                // Chains like a && b && c get lowered to AND(AND(a, b), c).
+                // In here, b and c are RHS, while a is the only LHS operand in
+                // that chain. This holds true for longer chains as well: the
+                // leading operand is always the only LHS operand that is not a
+                // binop itself. Putting a binop like AND(a, b) into a
+                // terminating scope is not useful, thus we only put the LHS
+                // into a terminating scope if it is not a binop.
+
+                let terminate_lhs = match l.kind {
+                    // let expressions can create temporaries that live on
+                    hir::ExprKind::Let(_) => false,
+                    // binops already drop their temporaries, so there is no
+                    // need to put them into a terminating scope.
+                    // This is purely an optimization to reduce the number of
+                    // terminating scopes.
+                    hir::ExprKind::Binary(
+                        source_map::Spanned {
+                            node: hir::BinOpKind::And | hir::BinOpKind::Or, ..
+                        },
+                        ..,
+                    ) => false,
+                    // otherwise: mark it as terminating
+                    _ => true,
+                };
+                if terminate_lhs {
+                    terminating(l.hir_id.local_id);
+                }
 
                 // `Let` expressions (in a let-chain) shouldn't be terminating, as their temporaries
                 // should live beyond the immediate expression
index 7daed74e9de83d6add8504792d4daad16ab468f9..69eb96fe8e9251871a8031c05f8278c5e2965dd3 100644 (file)
@@ -31,7 +31,6 @@
 };
 
 use std::cell::LazyCell;
-use std::convert::TryInto;
 use std::iter;
 use std::ops::{ControlFlow, Deref};
 
@@ -1544,7 +1543,7 @@ fn check_fn_or_method<'tcx>(
     check_where_clauses(wfcx, span, def_id);
 
     check_return_position_impl_trait_in_trait_bounds(
-        tcx,
+        wfcx,
         def_id,
         sig.output(),
         hir_decl.output.span(),
@@ -1580,13 +1579,14 @@ fn check_fn_or_method<'tcx>(
 
 /// Basically `check_associated_type_bounds`, but separated for now and should be
 /// deduplicated when RPITITs get lowered into real associated items.
-#[tracing::instrument(level = "trace", skip(tcx))]
+#[tracing::instrument(level = "trace", skip(wfcx))]
 fn check_return_position_impl_trait_in_trait_bounds<'tcx>(
-    tcx: TyCtxt<'tcx>,
+    wfcx: &WfCheckingCtxt<'_, 'tcx>,
     fn_def_id: LocalDefId,
     fn_output: Ty<'tcx>,
     span: Span,
 ) {
+    let tcx = wfcx.tcx();
     if let Some(assoc_item) = tcx.opt_associated_item(fn_def_id.to_def_id())
         && assoc_item.container == ty::AssocItemContainer::TraitContainer
     {
@@ -1596,22 +1596,20 @@ fn check_return_position_impl_trait_in_trait_bounds<'tcx>(
                 && tcx.def_kind(proj.item_def_id) == DefKind::ImplTraitPlaceholder
                 && tcx.impl_trait_in_trait_parent(proj.item_def_id) == fn_def_id.to_def_id()
             {
-                // Create a new context, since we want the opaque's ParamEnv and not the parent's.
                 let span = tcx.def_span(proj.item_def_id);
-                enter_wf_checking_ctxt(tcx, span, proj.item_def_id.expect_local(), |wfcx| {
-                    let bounds = wfcx.tcx().explicit_item_bounds(proj.item_def_id);
-                    let wf_obligations = bounds.iter().flat_map(|&(bound, bound_span)| {
-                        let normalized_bound = wfcx.normalize(span, None, bound);
-                        traits::wf::predicate_obligations(
-                            wfcx.infcx,
-                            wfcx.param_env,
-                            wfcx.body_id,
-                            normalized_bound,
-                            bound_span,
-                        )
-                    });
-                    wfcx.register_obligations(wf_obligations);
+                let bounds = wfcx.tcx().explicit_item_bounds(proj.item_def_id);
+                let wf_obligations = bounds.iter().flat_map(|&(bound, bound_span)| {
+                    let bound = ty::EarlyBinder(bound).subst(tcx, proj.substs);
+                    let normalized_bound = wfcx.normalize(span, None, bound);
+                    traits::wf::predicate_obligations(
+                        wfcx.infcx,
+                        wfcx.param_env,
+                        wfcx.body_id,
+                        normalized_bound,
+                        bound_span,
+                    )
                 });
+                wfcx.register_obligations(wf_obligations);
             }
         }
     }
index d0c31733481b63ef24e1f5a2e9cc54d37a6a03c9..5749b04783ce4ff8c7608e83771a3754471fffe4 100644 (file)
@@ -56,25 +56,6 @@ fn unused_crates_lint(tcx: TyCtxt<'_>) {
     let unused_extern_crates: FxHashMap<LocalDefId, Span> = tcx
         .maybe_unused_extern_crates(())
         .iter()
-        .filter(|&&(def_id, _)| {
-            // The `def_id` here actually was calculated during resolution (at least
-            // at the time of this writing) and is being shipped to us via a side
-            // channel of the tcx. There may have been extra expansion phases,
-            // however, which ended up removing the `def_id` *after* expansion.
-            //
-            // As a result we need to verify that `def_id` is indeed still valid for
-            // our AST and actually present in the HIR map. If it's not there then
-            // there's safely nothing to warn about, and otherwise we carry on with
-            // our execution.
-            //
-            // Note that if we carry through to the `extern_mod_stmt_cnum` query
-            // below it'll cause a panic because `def_id` is actually bogus at this
-            // point in time otherwise.
-            if tcx.hir().find(tcx.hir().local_def_id_to_hir_id(def_id)).is_none() {
-                return false;
-            }
-            true
-        })
         .filter(|&&(def_id, _)| {
             tcx.extern_mod_stmt_cnum(def_id).map_or(true, |cnum| {
                 !tcx.is_compiler_builtins(cnum)
index d623e726139442891d173b04829e287ede2cdc82..72288e5bc761f0e4ba9566e1f02c4d44d57f5420 100644 (file)
@@ -955,7 +955,7 @@ fn trait_def(tcx: TyCtxt<'_>, def_id: DefId) -> ty::TraitDef {
                     .struct_span_err(
                         attr.span,
                         "the `#[rustc_must_implement_one_of]` attribute must be \
-                        used with at least 2 args",
+                         used with at least 2 args",
                     )
                     .emit();
 
@@ -987,7 +987,7 @@ fn trait_def(tcx: TyCtxt<'_>, def_id: DefId) -> ty::TraitDef {
                             tcx.sess
                                 .struct_span_err(
                                     item.span,
-                                    "This function doesn't have a default implementation",
+                                    "function doesn't have a default implementation",
                                 )
                                 .span_note(attr_span, "required by this annotation")
                                 .emit();
@@ -999,17 +999,17 @@ fn trait_def(tcx: TyCtxt<'_>, def_id: DefId) -> ty::TraitDef {
                     }
                     Some(item) => {
                         tcx.sess
-                            .struct_span_err(item.span, "Not a function")
+                            .struct_span_err(item.span, "not a function")
                             .span_note(attr_span, "required by this annotation")
                             .note(
-                                "All `#[rustc_must_implement_one_of]` arguments \
-                            must be associated function names",
+                                "all `#[rustc_must_implement_one_of]` arguments must be associated \
+                                 function names",
                             )
                             .emit();
                     }
                     None => {
                         tcx.sess
-                            .struct_span_err(ident.span, "Function not found in this trait")
+                            .struct_span_err(ident.span, "function not found in this trait")
                             .emit();
                     }
                 }
@@ -1027,11 +1027,8 @@ fn trait_def(tcx: TyCtxt<'_>, def_id: DefId) -> ty::TraitDef {
             for ident in &*list {
                 if let Some(dup) = set.insert(ident.name, ident.span) {
                     tcx.sess
-                        .struct_span_err(vec![dup, ident.span], "Functions names are duplicated")
-                        .note(
-                            "All `#[rustc_must_implement_one_of]` arguments \
-                            must be unique",
-                        )
+                        .struct_span_err(vec![dup, ident.span], "functions names are duplicated")
+                        .note("all `#[rustc_must_implement_one_of]` arguments must be unique")
                         .emit();
 
                     no_dups = false;
@@ -1814,7 +1811,12 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: DefId) -> CodegenFnAttrs {
             );
         } else if attr.has_name(sym::linkage) {
             if let Some(val) = attr.value_str() {
-                codegen_fn_attrs.linkage = Some(linkage_by_name(tcx, did, val.as_str()));
+                let linkage = Some(linkage_by_name(tcx, did, val.as_str()));
+                if tcx.is_foreign_item(did) {
+                    codegen_fn_attrs.import_linkage = linkage;
+                } else {
+                    codegen_fn_attrs.linkage = linkage;
+                }
             }
         } else if attr.has_name(sym::link_section) {
             if let Some(val) = attr.value_str() {
@@ -1844,6 +1846,8 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: DefId) -> CodegenFnAttrs {
                         codegen_fn_attrs.no_sanitize |= SanitizerSet::ADDRESS;
                     } else if item.has_name(sym::cfi) {
                         codegen_fn_attrs.no_sanitize |= SanitizerSet::CFI;
+                    } else if item.has_name(sym::kcfi) {
+                        codegen_fn_attrs.no_sanitize |= SanitizerSet::KCFI;
                     } else if item.has_name(sym::memory) {
                         codegen_fn_attrs.no_sanitize |= SanitizerSet::MEMORY;
                     } else if item.has_name(sym::memtag) {
@@ -1857,7 +1861,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: DefId) -> CodegenFnAttrs {
                     } else {
                         tcx.sess
                             .struct_span_err(item.span(), "invalid argument for `no_sanitize`")
-                            .note("expected one of: `address`, `cfi`, `hwaddress`, `memory`, `memtag`, `shadow-call-stack`, or `thread`")
+                            .note("expected one of: `address`, `cfi`, `hwaddress`, `kcfi`, `memory`, `memtag`, `shadow-call-stack`, or `thread`")
                             .emit();
                     }
                 }
@@ -2073,6 +2077,11 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: DefId) -> CodegenFnAttrs {
         }
     }
 
+    if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::NAKED) {
+        codegen_fn_attrs.flags |= CodegenFnAttrFlags::NO_COVERAGE;
+        codegen_fn_attrs.inline = InlineAttr::Never;
+    }
+
     // Weak lang items have the same semantics as "std internal" symbols in the
     // sense that they're preserved through all our LTO passes and only
     // strippable by the linker.
index 639f81f20bfb9d2389ee19f73ae3cf2043e5087b..cb4c35c0ce177e527e1bab8feba86b319ce53878 100644 (file)
@@ -4,7 +4,6 @@
     GenericParamKind, HirId, Node,
 };
 use rustc_hir as hir;
-use rustc_hir::def::DefKind;
 use rustc_hir::def_id::DefId;
 use rustc_middle::ty::{self, TyCtxt};
 use rustc_session::lint;
@@ -79,7 +78,7 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics {
                     let generics = tcx.generics_of(parent_def_id.to_def_id());
                     let param_def_idx = generics.param_def_id_to_index[&param_id.to_def_id()];
                     // In the above example this would be .params[..N#0]
-                    let params = generics.params[..param_def_idx as usize].to_owned();
+                    let params = generics.params_to(param_def_idx as usize, tcx).to_owned();
                     let param_def_id_to_index =
                         params.iter().map(|param| (param.def_id, param.index)).collect();
 
@@ -143,20 +142,7 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics {
             Some(tcx.typeck_root_def_id(def_id))
         }
         Node::Item(item) => match item.kind {
-            ItemKind::OpaqueTy(hir::OpaqueTy {
-                origin:
-                    hir::OpaqueTyOrigin::FnReturn(fn_def_id) | hir::OpaqueTyOrigin::AsyncFn(fn_def_id),
-                in_trait,
-                ..
-            }) => {
-                if in_trait {
-                    assert!(matches!(tcx.def_kind(fn_def_id), DefKind::AssocFn))
-                } else {
-                    assert!(matches!(tcx.def_kind(fn_def_id), DefKind::AssocFn | DefKind::Fn))
-                }
-                Some(fn_def_id.to_def_id())
-            }
-            ItemKind::OpaqueTy(hir::OpaqueTy { origin: hir::OpaqueTyOrigin::TyAlias, .. }) => {
+            ItemKind::OpaqueTy(hir::OpaqueTy { .. }) => {
                 let parent_id = tcx.hir().get_parent_item(hir_id);
                 assert_ne!(parent_id, hir::CRATE_OWNER_ID);
                 debug!("generics_of: parent of opaque ty {:?} is {:?}", def_id, parent_id);
index c11eed7ad9e57cd315c94a0746d1d334198f272f..9a7b261fffd4ded6cde9bc8bee5f84f8af042336 100644 (file)
@@ -814,7 +814,7 @@ fn visit_lifetime(&mut self, lifetime_ref: &'tcx hir::Lifetime) {
         }
     }
 
-    fn visit_path(&mut self, path: &'tcx hir::Path<'tcx>, _: hir::HirId) {
+    fn visit_path(&mut self, path: &hir::Path<'tcx>, _: hir::HirId) {
         for (i, segment) in path.segments.iter().enumerate() {
             let depth = path.segments.len() - i - 1;
             if let Some(ref args) = segment.args {
index afbb27155a2f59f7deb2c49acf44acc590e7c376..c92ab749bc1f7dc4a7e44023f684401aecde76b7 100644 (file)
@@ -43,6 +43,10 @@ pub struct LifetimesOrBoundsMismatchOnTrait {
     pub span: Span,
     #[label(generics_label)]
     pub generics_span: Option<Span>,
+    #[label(where_label)]
+    pub where_span: Option<Span>,
+    #[label(bounds_label)]
+    pub bounds_span: Vec<Span>,
     pub item_kind: &'static str,
     pub ident: Ident,
 }
@@ -285,3 +289,10 @@ pub struct SelfInImplSelf {
     #[note]
     pub note: (),
 }
+
+#[derive(Diagnostic)]
+#[diag(hir_analysis_linkage_type, code = "E0791")]
+pub(crate) struct LinkageType {
+    #[primary_span]
+    pub span: Span,
+}
index 9db05eedbde790e43c2e3c6fa081179424edc3f6..8b2719c2f8aaaef1add2f372c81751f7b6bdc8c2 100644 (file)
@@ -7,7 +7,8 @@
 use rustc_hir::def::DefKind;
 use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_middle::ty::query::Providers;
-use rustc_middle::ty::{self, CrateVariancesMap, TyCtxt, TypeSuperVisitable, TypeVisitable};
+use rustc_middle::ty::{self, CrateVariancesMap, SubstsRef, Ty, TyCtxt};
+use rustc_middle::ty::{DefIdTree, TypeSuperVisitable, TypeVisitable};
 use std::ops::ControlFlow;
 
 /// Defines the `TermsContext` basically houses an arena where we can
@@ -75,11 +76,30 @@ fn variance_of_opaque(tcx: TyCtxt<'_>, item_def_id: LocalDefId) -> &[ty::Varianc
     // type Foo<'a, 'b, 'c> = impl Trait<'a> + 'b;
     // ```
     // we may not use `'c` in the hidden type.
-    struct OpaqueTypeLifetimeCollector {
+    struct OpaqueTypeLifetimeCollector<'tcx> {
+        tcx: TyCtxt<'tcx>,
+        root_def_id: DefId,
         variances: Vec<ty::Variance>,
     }
 
-    impl<'tcx> ty::TypeVisitor<'tcx> for OpaqueTypeLifetimeCollector {
+    impl<'tcx> OpaqueTypeLifetimeCollector<'tcx> {
+        #[instrument(level = "trace", skip(self), ret)]
+        fn visit_opaque(&mut self, def_id: DefId, substs: SubstsRef<'tcx>) -> ControlFlow<!> {
+            if def_id != self.root_def_id && self.tcx.is_descendant_of(def_id, self.root_def_id) {
+                let child_variances = self.tcx.variances_of(def_id);
+                for (a, v) in substs.iter().zip(child_variances) {
+                    if *v != ty::Bivariant {
+                        a.visit_with(self)?;
+                    }
+                }
+                ControlFlow::CONTINUE
+            } else {
+                substs.visit_with(self)
+            }
+        }
+    }
+
+    impl<'tcx> ty::TypeVisitor<'tcx> for OpaqueTypeLifetimeCollector<'tcx> {
         #[instrument(level = "trace", skip(self), ret)]
         fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
             if let ty::RegionKind::ReEarlyBound(ebr) = r.kind() {
@@ -87,6 +107,19 @@ fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
             }
             r.super_visit_with(self)
         }
+
+        #[instrument(level = "trace", skip(self), ret)]
+        fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
+            match t.kind() {
+                ty::Opaque(def_id, substs) => self.visit_opaque(*def_id, substs),
+                ty::Projection(proj)
+                    if self.tcx.def_kind(proj.item_def_id) == DefKind::ImplTraitPlaceholder =>
+                {
+                    self.visit_opaque(proj.item_def_id, proj.substs)
+                }
+                _ => t.super_visit_with(self),
+            }
+        }
     }
 
     // By default, RPIT are invariant wrt type and const generics, but they are bivariant wrt
@@ -111,7 +144,8 @@ fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
         }
     }
 
-    let mut collector = OpaqueTypeLifetimeCollector { variances };
+    let mut collector =
+        OpaqueTypeLifetimeCollector { tcx, root_def_id: item_def_id.to_def_id(), variances };
     let id_substs = ty::InternalSubsts::identity_for_item(tcx, item_def_id.to_def_id());
     for pred in tcx.bound_explicit_item_bounds(item_def_id.to_def_id()).transpose_iter() {
         let pred = pred.map_bound(|(pred, _)| *pred).subst(tcx, id_substs);
index 81d933b8e7f0f21a458ab7194d7f7a8d6e60366f..ef98c4ba54cbdfd1e3a6c1a0b0401beb5ab2a5e8 100644 (file)
@@ -695,19 +695,8 @@ pub fn print_item(&mut self, item: &hir::Item<'_>) {
                 self.head("trait");
                 self.print_ident(item.ident);
                 self.print_generic_params(generics.params);
-                let mut real_bounds = Vec::with_capacity(bounds.len());
-                // FIXME(durka) this seems to be some quite outdated syntax
-                for b in bounds {
-                    if let GenericBound::Trait(ptr, hir::TraitBoundModifier::Maybe) = b {
-                        self.space();
-                        self.word_space("for ?");
-                        self.print_trait_ref(&ptr.trait_ref);
-                    } else {
-                        real_bounds.push(b);
-                    }
-                }
                 self.nbsp();
-                self.print_bounds("=", real_bounds);
+                self.print_bounds("=", bounds);
                 self.print_where_clause(generics);
                 self.word(";");
                 self.end(); // end inner head-block
@@ -1480,6 +1469,7 @@ pub fn print_expr(&mut self, expr: &hir::Expr<'_>) {
                 fn_decl,
                 body,
                 fn_decl_span: _,
+                fn_arg_span: _,
                 movability: _,
                 def_id: _,
             }) => {
@@ -1591,7 +1581,7 @@ pub fn print_name(&mut self, name: Symbol) {
         self.print_ident(Ident::with_dummy_span(name))
     }
 
-    pub fn print_path(&mut self, path: &hir::Path<'_>, colons_before_params: bool) {
+    pub fn print_path<R>(&mut self, path: &hir::Path<'_, R>, colons_before_params: bool) {
         self.maybe_print_comment(path.span.lo());
 
         for (i, segment) in path.segments.iter().enumerate() {
index b09ddf80e2a52577292e3d602fca7e3cff198dc2..7a5191b77f1d45759a88ce6f7c6740f1b257df6d 100644 (file)
@@ -521,7 +521,7 @@ fn suggest_call_as_method(
                 callee_expr,
                 call_expr,
                 callee_ty,
-                pick,
+                &pick,
                 segment,
             );
             if pick.illegal_sized_bound.is_some() {
index 0c9a350c295f4227866c20eb5e4ae887b027ed7d..32f86b8042c11c39d36baa268dc8cb40d1c1a1c3 100644 (file)
@@ -1,7 +1,7 @@
 use crate::coercion::CoerceMany;
 use crate::gather_locals::GatherLocalsVisitor;
 use crate::FnCtxt;
-use crate::{GeneratorTypes, UnsafetyState};
+use crate::GeneratorTypes;
 use rustc_hir as hir;
 use rustc_hir::def::DefKind;
 use rustc_hir::intravisit::Visitor;
@@ -30,7 +30,6 @@ pub(super) fn check_fn<'a, 'tcx>(
     can_be_generator: Option<hir::Movability>,
 ) -> Option<GeneratorTypes<'tcx>> {
     let fn_id = fcx.tcx.hir().local_def_id_to_hir_id(fn_def_id);
-    fcx.ps.set(UnsafetyState::function(fn_sig.unsafety, fn_id));
 
     let tcx = fcx.tcx;
     let hir = tcx.hir();
index 5d3419b3b6e66c16be7e11c09dc0d0630ef0454c..429cb60ba2b6161692c9153041a068ce638e69d5 100644 (file)
@@ -456,10 +456,11 @@ fn sig_of_closure_with_mismatched_number_of_arguments(
             .iter()
             .map(|ty| ArgKind::from_expected_ty(*ty, None))
             .collect();
-        let (closure_span, found_args) = match self.get_fn_like_arguments(expr_map_node) {
-            Some((sp, args)) => (Some(sp), args),
-            None => (None, Vec::new()),
-        };
+        let (closure_span, closure_arg_span, found_args) =
+            match self.get_fn_like_arguments(expr_map_node) {
+                Some((sp, arg_sp, args)) => (Some(sp), arg_sp, args),
+                None => (None, None, Vec::new()),
+            };
         let expected_span =
             expected_sig.cause_span.unwrap_or_else(|| self.tcx.def_span(expr_def_id));
         self.report_arg_count_mismatch(
@@ -468,6 +469,7 @@ fn sig_of_closure_with_mismatched_number_of_arguments(
             expected_args,
             found_args,
             true,
+            closure_arg_span,
         )
         .emit();
 
index 24184bdbf5cdcd74b125f185243919086905910f..6763e06c0cfeed38a2a5c83f7fecb58c47beb825 100644 (file)
@@ -189,7 +189,7 @@ fn annotate_expected_due_to_let_ty(
         &self,
         err: &mut Diagnostic,
         expr: &hir::Expr<'_>,
-        error: Option<TypeError<'_>>,
+        error: Option<TypeError<'tcx>>,
     ) {
         let parent = self.tcx.hir().get_parent_node(expr.hir_id);
         match (self.tcx.hir().find(parent), error) {
@@ -286,6 +286,16 @@ fn annotate_expected_due_to_let_ty(
                     err.downgrade_to_delayed_bug();
                 }
             }
+            (
+                Some(hir::Node::Expr(hir::Expr {
+                    kind: hir::ExprKind::Binary(_, lhs, rhs), ..
+                })),
+                Some(TypeError::Sorts(ExpectedFound { expected, .. })),
+            ) if rhs.hir_id == expr.hir_id
+                && self.typeck_results.borrow().expr_ty_adjusted_opt(lhs) == Some(expected) =>
+            {
+                err.span_label(lhs.span, &format!("expected because this is `{expected}`"));
+            }
             _ => {}
         }
     }
index 0c5bbb3e20be32cc3a83e063e1d36006be387b30..ed87b94a040d0f87b4d665898481ea2efa3c10d9 100644 (file)
@@ -528,6 +528,7 @@ pub(crate) fn check_expr_path(
             self.resolve_ty_and_res_fully_qualified_call(qpath, expr.hir_id, expr.span);
         let ty = match res {
             Res::Err => {
+                self.suggest_assoc_method_call(segs);
                 let e =
                     self.tcx.sess.delay_span_bug(qpath.span(), "`Res::Err` but no error emitted");
                 self.set_tainted_by_errors(e);
@@ -1646,6 +1647,9 @@ fn check_expr_struct_fields(
         // the fields with the base_expr. This could cause us to hit errors later
         // when certain fields are assumed to exist that in fact do not.
         if error_happened {
+            if let Some(base_expr) = base_expr {
+                self.check_expr(base_expr);
+            }
             return;
         }
 
index e5e798f4b933f2ec18ae1dc5bdc8c4e6bd411cbe..03b174c77955fb400eab47aa6071b3cec6bef94a 100644 (file)
@@ -523,6 +523,11 @@ fn walk_struct_expr<'hir>(
         // Consume the expressions supplying values for each field.
         for field in fields {
             self.consume_expr(field.expr);
+
+            // The struct path probably didn't resolve
+            if self.mc.typeck_results.opt_field_index(field.hir_id).is_none() {
+                self.tcx().sess.delay_span_bug(field.span, "couldn't resolve index for field");
+            }
         }
 
         let with_expr = match *opt_with {
@@ -540,9 +545,9 @@ fn walk_struct_expr<'hir>(
             ty::Adt(adt, substs) if adt.is_struct() => {
                 // Consume those fields of the with expression that are needed.
                 for (f_index, with_field) in adt.non_enum_variant().fields.iter().enumerate() {
-                    let is_mentioned = fields.iter().any(|f| {
-                        self.tcx().field_index(f.hir_id, self.mc.typeck_results) == f_index
-                    });
+                    let is_mentioned = fields
+                        .iter()
+                        .any(|f| self.mc.typeck_results.opt_field_index(f.hir_id) == Some(f_index));
                     if !is_mentioned {
                         let field_place = self.mc.cat_projection(
                             &*with_expr,
index 0d6b0175406feaed7655e9f93b2e5b81a777638d..93618c61417300b5957792e262c614d14311f178 100644 (file)
@@ -1393,8 +1393,6 @@ pub(in super::super) fn check_block_with_expected(
         blk: &'tcx hir::Block<'tcx>,
         expected: Expectation<'tcx>,
     ) -> Ty<'tcx> {
-        let prev = self.ps.replace(self.ps.get().recurse(blk));
-
         // In some cases, blocks have just one exit, but other blocks
         // can be targeted by multiple breaks. This can happen both
         // with labeled blocks as well as when we desugar
@@ -1558,7 +1556,6 @@ pub(in super::super) fn check_block_with_expected(
 
         self.write_ty(blk.hir_id, ty);
 
-        self.ps.set(prev);
         ty
     }
 
@@ -1918,7 +1915,11 @@ fn point_at_arg_if_possible(
         receiver: Option<&'tcx hir::Expr<'tcx>>,
         args: &'tcx [hir::Expr<'tcx>],
     ) -> bool {
-        let sig = self.tcx.fn_sig(def_id).skip_binder();
+        let ty = self.tcx.type_of(def_id);
+        if !ty.is_fn() {
+            return false;
+        }
+        let sig = ty.fn_sig(self.tcx).skip_binder();
         let args_referencing_param: Vec<_> = sig
             .inputs()
             .iter()
index ea141e815bf4a9c268d1f3652f20a795863c137b..30b59da7852d46f1e96543ef7566668e00834910 100644 (file)
@@ -8,7 +8,7 @@
 pub use suggestions::*;
 
 use crate::coercion::DynamicCoerceMany;
-use crate::{Diverges, EnclosingBreakables, Inherited, UnsafetyState};
+use crate::{Diverges, EnclosingBreakables, Inherited};
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
 use rustc_hir_analysis::astconv::AstConv;
@@ -22,7 +22,7 @@
 use rustc_session::Session;
 use rustc_span::symbol::Ident;
 use rustc_span::{self, Span};
-use rustc_trait_selection::traits::{ObligationCause, ObligationCauseCode};
+use rustc_trait_selection::traits::{ObligationCause, ObligationCauseCode, ObligationCtxt};
 
 use std::cell::{Cell, RefCell};
 use std::ops::Deref;
@@ -74,8 +74,6 @@ pub struct FnCtxt<'a, 'tcx> {
 
     pub(super) resume_yield_tys: Option<(Ty<'tcx>, Ty<'tcx>)>,
 
-    pub(super) ps: Cell<UnsafetyState>,
-
     /// Whether the last checked node generates a divergence (e.g.,
     /// `return` will set this to `Always`). In general, when entering
     /// an expression or other node in the tree, the initial value
@@ -129,7 +127,6 @@ pub fn new(
             ret_coercion: None,
             ret_coercion_span: Cell::new(None),
             resume_yield_tys: None,
-            ps: Cell::new(UnsafetyState::function(hir::Unsafety::Normal, hir::CRATE_HIR_ID)),
             diverges: Cell::new(Diverges::Maybe),
             enclosing_breakables: RefCell::new(EnclosingBreakables {
                 stack: Vec::new(),
@@ -162,6 +159,23 @@ pub fn err_ctxt(&'a self) -> TypeErrCtxt<'a, 'tcx> {
             infcx: &self.infcx,
             typeck_results: Some(self.typeck_results.borrow()),
             fallback_has_occurred: self.fallback_has_occurred.get(),
+            normalize_fn_sig: Box::new(|fn_sig| {
+                if fn_sig.has_escaping_bound_vars() {
+                    return fn_sig;
+                }
+                self.probe(|_| {
+                    let ocx = ObligationCtxt::new_in_snapshot(self);
+                    let normalized_fn_sig =
+                        ocx.normalize(&ObligationCause::dummy(), self.param_env, fn_sig);
+                    if ocx.select_all_or_error().is_empty() {
+                        let normalized_fn_sig = self.resolve_vars_if_possible(normalized_fn_sig);
+                        if !normalized_fn_sig.needs_infer() {
+                            return normalized_fn_sig;
+                        }
+                    }
+                    fn_sig
+                })
+            }),
         }
     }
 
index b9a8d16311c93a7f0465c5035f37c95d19375ca8..4f92477b5d87ef221239c71054742025efb7bf32 100644 (file)
@@ -10,7 +10,7 @@
     Expr, ExprKind, GenericBound, Node, Path, QPath, Stmt, StmtKind, TyKind, WherePredicate,
 };
 use rustc_hir_analysis::astconv::AstConv;
-use rustc_infer::infer::{self, TyCtxtInferExt};
+use rustc_infer::infer;
 use rustc_infer::traits::{self, StatementAsExpression};
 use rustc_middle::lint::in_external_macro;
 use rustc_middle::ty::{self, Binder, DefIdTree, IsSuggestable, ToPredicate, Ty};
@@ -32,11 +32,13 @@ pub(crate) fn body_fn_sig(&self) -> Option<ty::FnSig<'tcx>> {
     }
 
     pub(in super::super) fn suggest_semicolon_at_end(&self, span: Span, err: &mut Diagnostic) {
+        // This suggestion is incorrect for
+        // fn foo() -> bool { match () { () => true } || match () { () => true } }
         err.span_suggestion_short(
             span.shrink_to_hi(),
             "consider using a semicolon here",
             ";",
-            Applicability::MachineApplicable,
+            Applicability::MaybeIncorrect,
         );
     }
 
@@ -921,19 +923,13 @@ pub(in super::super) fn suggest_missing_break_or_return_expr(
             let ty = <dyn AstConv<'_>>::ast_ty_to_ty(self, ty);
             let bound_vars = self.tcx.late_bound_vars(fn_id);
             let ty = self.tcx.erase_late_bound_regions(Binder::bind_with_vars(ty, bound_vars));
-            let ty = self.normalize(expr.span, ty);
             let ty = match self.tcx.asyncness(fn_id.owner) {
-                hir::IsAsync::Async => {
-                    let infcx = self.tcx.infer_ctxt().build();
-                    infcx.get_impl_future_output_ty(ty).unwrap_or_else(|| {
-                        span_bug!(
-                            fn_decl.output.span(),
-                            "failed to get output type of async function"
-                        )
-                    })
-                }
+                hir::IsAsync::Async => self.get_impl_future_output_ty(ty).unwrap_or_else(|| {
+                    span_bug!(fn_decl.output.span(), "failed to get output type of async function")
+                }),
                 hir::IsAsync::NotAsync => ty,
             };
+            let ty = self.normalize(expr.span, ty);
             if self.can_coerce(found, ty) {
                 err.multipart_suggestion(
                     "you might have meant to return this value",
index 869ad07c00d61a8511b55f28f9af7d9315907950..b33e7b8d68cf927251a4e85a9c57a672fcabf9b5 100644 (file)
@@ -1,7 +1,6 @@
 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;
@@ -11,9 +10,7 @@
 use rustc_middle::ty::{self, Ty, TyCtxt};
 use rustc_span::def_id::LocalDefIdMap;
 use rustc_span::{self, Span};
-use rustc_trait_selection::traits::{
-    self, ObligationCause, ObligationCtxt, TraitEngine, TraitEngineExt as _,
-};
+use rustc_trait_selection::traits::{self, TraitEngine, TraitEngineExt as _};
 
 use std::cell::RefCell;
 use std::ops::Deref;
@@ -92,29 +89,7 @@ pub fn build(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> InheritedBuilder<'tcx> {
             infcx: tcx
                 .infer_ctxt()
                 .ignoring_regions()
-                .with_opaque_type_inference(DefiningAnchor::Bind(hir_owner.def_id))
-                .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
-                    })
-                })),
+                .with_opaque_type_inference(DefiningAnchor::Bind(hir_owner.def_id)),
             def_id,
             typeck_results: RefCell::new(ty::TypeckResults::new(hir_owner)),
         }
index 09bd123350dfd1e3f794a4f7e13210a7acf50f3e..5b2352cda34b3ee5fa9bcfa2f98d11acee4af2c4 100644 (file)
@@ -89,38 +89,6 @@ pub struct LocalTy<'tcx> {
     revealed_ty: Ty<'tcx>,
 }
 
-#[derive(Copy, Clone)]
-pub struct UnsafetyState {
-    pub def: hir::HirId,
-    pub unsafety: hir::Unsafety,
-    from_fn: bool,
-}
-
-impl UnsafetyState {
-    pub fn function(unsafety: hir::Unsafety, def: hir::HirId) -> UnsafetyState {
-        UnsafetyState { def, unsafety, from_fn: true }
-    }
-
-    pub fn recurse(self, blk: &hir::Block<'_>) -> UnsafetyState {
-        use hir::BlockCheckMode;
-        match self.unsafety {
-            // If this unsafe, then if the outer function was already marked as
-            // unsafe we shouldn't attribute the unsafe'ness to the block. This
-            // way the block can be warned about instead of ignoring this
-            // extraneous block (functions are never warned about).
-            hir::Unsafety::Unsafe if self.from_fn => self,
-
-            unsafety => {
-                let (unsafety, def) = match blk.rules {
-                    BlockCheckMode::UnsafeBlock(..) => (hir::Unsafety::Unsafe, blk.hir_id),
-                    BlockCheckMode::DefaultBlock => (unsafety, self.def),
-                };
-                UnsafetyState { def, unsafety, from_fn: false }
-            }
-        }
-    }
-}
-
 /// If this `DefId` is a "primary tables entry", returns
 /// `Some((body_id, body_ty, fn_sig))`. Otherwise, returns `None`.
 ///
index 03d0e7926de1166fc5103cc7f0167ea4eb153048..218c54688aa3e959a187f7b69aded369e9ab8a99 100644 (file)
@@ -45,7 +45,7 @@ pub fn confirm_method(
         self_expr: &'tcx hir::Expr<'tcx>,
         call_expr: &'tcx hir::Expr<'tcx>,
         unadjusted_self_ty: Ty<'tcx>,
-        pick: probe::Pick<'tcx>,
+        pick: &probe::Pick<'tcx>,
         segment: &hir::PathSegment<'_>,
     ) -> ConfirmResult<'tcx> {
         debug!(
@@ -71,7 +71,7 @@ fn new(
     fn confirm(
         &mut self,
         unadjusted_self_ty: Ty<'tcx>,
-        pick: probe::Pick<'tcx>,
+        pick: &probe::Pick<'tcx>,
         segment: &hir::PathSegment<'_>,
     ) -> ConfirmResult<'tcx> {
         // Adjust the self expression the user provided and obtain the adjusted type.
index ebbd5eb1e6478cafdb717373c908f1f5724ff01b..b15c086ffad5781f2b921dd61d5c97b31d8bb470 100644 (file)
@@ -20,7 +20,7 @@
 use rustc_infer::infer::{self, InferOk};
 use rustc_middle::traits::ObligationCause;
 use rustc_middle::ty::subst::{InternalSubsts, SubstsRef};
-use rustc_middle::ty::{self, DefIdTree, GenericParamDefKind, Ty, TypeVisitable};
+use rustc_middle::ty::{self, GenericParamDefKind, Ty, TypeVisitable};
 use rustc_span::symbol::Ident;
 use rustc_span::Span;
 use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
@@ -192,8 +192,7 @@ pub fn lookup_method(
 
         self.tcx.check_stability(pick.item.def_id, Some(call_expr.hir_id), span, None);
 
-        let result =
-            self.confirm_method(span, self_expr, call_expr, self_ty, pick.clone(), segment);
+        let result = self.confirm_method(span, self_expr, call_expr, self_ty, &pick, segment);
         debug!("result = {:?}", result);
 
         if let Some(span) = result.illegal_sized_bound {
@@ -217,7 +216,7 @@ pub fn lookup_method(
             }
 
             // We probe again, taking all traits into account (not only those in scope).
-            let mut candidates =
+            let candidates =
                 match self.lookup_probe(segment.ident, self_ty, call_expr, ProbeScope::AllTraits) {
                     // If we find a different result the caller probably forgot to import a trait.
                     Ok(ref new_pick) if pick.differs_from(new_pick) => {
@@ -236,7 +235,6 @@ pub fn lookup_method(
                         .collect(),
                     _ => Vec::new(),
                 };
-            candidates.retain(|candidate| *candidate != self.tcx.parent(result.callee.def_id));
 
             return Err(IllegalSizedBound(candidates, needs_mut, span));
         }
index c78a32c29dcdafe1bba9f32eaf3bc0b4e5d25cea..070359e71becc13381d15e12fb510b336a58c28e 100644 (file)
@@ -9,7 +9,6 @@
 use rustc_errors::Applicability;
 use rustc_hir as hir;
 use rustc_hir::def::DefKind;
-use rustc_hir::def::Namespace;
 use rustc_infer::infer::canonical::OriginalQueryValues;
 use rustc_infer::infer::canonical::{Canonical, QueryResponse};
 use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
@@ -39,9 +38,9 @@
 use rustc_trait_selection::traits::query::CanonicalTyGoal;
 use rustc_trait_selection::traits::NormalizeExt;
 use rustc_trait_selection::traits::{self, ObligationCause};
+use std::cell::RefCell;
 use std::cmp::max;
 use std::iter;
-use std::mem;
 use std::ops::Deref;
 
 use smallvec::{smallvec, SmallVec};
@@ -63,28 +62,29 @@ struct ProbeContext<'a, 'tcx> {
 
     /// This is the OriginalQueryValues for the steps queries
     /// that are answered in steps.
-    orig_steps_var_values: OriginalQueryValues<'tcx>,
+    orig_steps_var_values: &'a OriginalQueryValues<'tcx>,
     steps: &'tcx [CandidateStep<'tcx>],
 
     inherent_candidates: Vec<Candidate<'tcx>>,
     extension_candidates: Vec<Candidate<'tcx>>,
     impl_dups: FxHashSet<DefId>,
 
-    /// Collects near misses when the candidate functions are missing a `self` keyword and is only
-    /// used for error reporting
-    static_candidates: Vec<CandidateSource>,
-
     /// When probing for names, include names that are close to the
-    /// requested name (by Levensthein distance)
+    /// requested name (by Levenshtein distance)
     allow_similar_names: bool,
 
     /// Some(candidate) if there is a private candidate
     private_candidate: Option<(DefKind, DefId)>,
 
+    /// Collects near misses when the candidate functions are missing a `self` keyword and is only
+    /// used for error reporting
+    static_candidates: RefCell<Vec<CandidateSource>>,
+
     /// Collects near misses when trait bounds for type parameters are unsatisfied and is only used
     /// for error reporting
-    unsatisfied_predicates:
+    unsatisfied_predicates: RefCell<
         Vec<(ty::Predicate<'tcx>, Option<ty::Predicate<'tcx>>, Option<ObligationCause<'tcx>>)>,
+    >,
 
     scope_expr_id: hir::HirId,
 }
@@ -335,7 +335,7 @@ fn probe_op<OP, R>(
         op: OP,
     ) -> Result<R, MethodError<'tcx>>
     where
-        OP: FnOnce(ProbeContext<'a, 'tcx>) -> Result<R, MethodError<'tcx>>,
+        OP: FnOnce(ProbeContext<'_, 'tcx>) -> Result<R, MethodError<'tcx>>,
     {
         let mut orig_values = OriginalQueryValues::default();
         let param_env_and_self_ty = self.canonicalize_query(
@@ -446,7 +446,7 @@ fn probe_op<OP, R>(
                 mode,
                 method_name,
                 return_type,
-                orig_values,
+                &orig_values,
                 steps.steps,
                 scope_expr_id,
             );
@@ -540,7 +540,7 @@ fn new(
         mode: Mode,
         method_name: Option<Ident>,
         return_type: Option<Ty<'tcx>>,
-        orig_steps_var_values: OriginalQueryValues<'tcx>,
+        orig_steps_var_values: &'a OriginalQueryValues<'tcx>,
         steps: &'tcx [CandidateStep<'tcx>],
         scope_expr_id: hir::HirId,
     ) -> ProbeContext<'a, 'tcx> {
@@ -555,10 +555,10 @@ fn new(
             impl_dups: FxHashSet::default(),
             orig_steps_var_values,
             steps,
-            static_candidates: Vec::new(),
             allow_similar_names: false,
             private_candidate: None,
-            unsatisfied_predicates: Vec::new(),
+            static_candidates: RefCell::new(Vec::new()),
+            unsatisfied_predicates: RefCell::new(Vec::new()),
             scope_expr_id,
         }
     }
@@ -567,8 +567,9 @@ fn reset(&mut self) {
         self.inherent_candidates.clear();
         self.extension_candidates.clear();
         self.impl_dups.clear();
-        self.static_candidates.clear();
         self.private_candidate = None;
+        self.static_candidates.borrow_mut().clear();
+        self.unsatisfied_predicates.borrow_mut().clear();
     }
 
     ///////////////////////////////////////////////////////////////////////////
@@ -1004,9 +1005,9 @@ fn pick(mut self) -> PickResult<'tcx> {
 
         debug!("pick: actual search failed, assemble diagnostics");
 
-        let static_candidates = mem::take(&mut self.static_candidates);
+        let static_candidates = std::mem::take(self.static_candidates.get_mut());
         let private_candidate = self.private_candidate.take();
-        let unsatisfied_predicates = mem::take(&mut self.unsatisfied_predicates);
+        let unsatisfied_predicates = std::mem::take(self.unsatisfied_predicates.get_mut());
 
         // things failed, so lets look at all traits, for diagnostic purposes now:
         self.reset();
@@ -1051,7 +1052,7 @@ fn pick(mut self) -> PickResult<'tcx> {
         }))
     }
 
-    fn pick_core(&mut self) -> Option<PickResult<'tcx>> {
+    fn pick_core(&self) -> Option<PickResult<'tcx>> {
         let pick = self.pick_all_method(Some(&mut vec![]));
 
         // In this case unstable picking is done by `pick_method`.
@@ -1066,11 +1067,10 @@ fn pick_core(&mut self) -> Option<PickResult<'tcx>> {
     }
 
     fn pick_all_method(
-        &mut self,
+        &self,
         mut unstable_candidates: Option<&mut Vec<(Candidate<'tcx>, Symbol)>>,
     ) -> Option<PickResult<'tcx>> {
-        let steps = self.steps.clone();
-        steps
+        self.steps
             .iter()
             .filter(|step| {
                 debug!("pick_all_method: step={:?}", step);
@@ -1124,7 +1124,7 @@ fn pick_all_method(
     /// to transparently pass `&mut` pointers, in particular, without consuming
     /// them for their entire lifetime.
     fn pick_by_value_method(
-        &mut self,
+        &self,
         step: &CandidateStep<'tcx>,
         self_ty: Ty<'tcx>,
         unstable_candidates: Option<&mut Vec<(Candidate<'tcx>, Symbol)>>,
@@ -1152,7 +1152,7 @@ fn pick_by_value_method(
     }
 
     fn pick_autorefd_method(
-        &mut self,
+        &self,
         step: &CandidateStep<'tcx>,
         self_ty: Ty<'tcx>,
         mutbl: hir::Mutability,
@@ -1178,7 +1178,7 @@ fn pick_autorefd_method(
     /// special case for this is because going from `*mut T` to `*const T` with autoderefs and
     /// autorefs would require dereferencing the pointer, which is not safe.
     fn pick_const_ptr_method(
-        &mut self,
+        &self,
         step: &CandidateStep<'tcx>,
         self_ty: Ty<'tcx>,
         unstable_candidates: Option<&mut Vec<(Candidate<'tcx>, Symbol)>>,
@@ -1203,7 +1203,7 @@ fn pick_const_ptr_method(
         })
     }
 
-    fn pick_method_with_unstable(&mut self, self_ty: Ty<'tcx>) -> Option<PickResult<'tcx>> {
+    fn pick_method_with_unstable(&self, self_ty: Ty<'tcx>) -> Option<PickResult<'tcx>> {
         debug!("pick_method_with_unstable(self_ty={})", self.ty_to_string(self_ty));
 
         let mut possibly_unsatisfied_predicates = Vec::new();
@@ -1214,7 +1214,7 @@ fn pick_method_with_unstable(&mut self, self_ty: Ty<'tcx>) -> Option<PickResult<
             debug!("searching {} candidates", kind);
             let res = self.consider_candidates(
                 self_ty,
-                candidates.iter(),
+                candidates,
                 &mut possibly_unsatisfied_predicates,
                 Some(&mut vec![]),
             );
@@ -1223,21 +1223,27 @@ fn pick_method_with_unstable(&mut self, self_ty: Ty<'tcx>) -> Option<PickResult<
             }
         }
 
-        debug!("searching unstable candidates");
-        let res = self.consider_candidates(
-            self_ty,
-            self.inherent_candidates.iter().chain(&self.extension_candidates),
-            &mut possibly_unsatisfied_predicates,
-            None,
-        );
-        if res.is_none() {
-            self.unsatisfied_predicates.extend(possibly_unsatisfied_predicates);
+        for (kind, candidates) in
+            &[("inherent", &self.inherent_candidates), ("extension", &self.extension_candidates)]
+        {
+            debug!("searching unstable {kind} candidates");
+            let res = self.consider_candidates(
+                self_ty,
+                candidates,
+                &mut possibly_unsatisfied_predicates,
+                None,
+            );
+            if res.is_some() {
+                return res;
+            }
         }
-        res
+
+        self.unsatisfied_predicates.borrow_mut().extend(possibly_unsatisfied_predicates);
+        None
     }
 
     fn pick_method(
-        &mut self,
+        &self,
         self_ty: Ty<'tcx>,
         mut unstable_candidates: Option<&mut Vec<(Candidate<'tcx>, Symbol)>>,
     ) -> Option<PickResult<'tcx>> {
@@ -1255,7 +1261,7 @@ fn pick_method(
             debug!("searching {} candidates", kind);
             let res = self.consider_candidates(
                 self_ty,
-                candidates.iter(),
+                candidates,
                 &mut possibly_unsatisfied_predicates,
                 unstable_candidates.as_deref_mut(),
             );
@@ -1267,28 +1273,24 @@ fn pick_method(
         // `pick_method` may be called twice for the same self_ty if no stable methods
         // match. Only extend once.
         if unstable_candidates.is_some() {
-            self.unsatisfied_predicates.extend(possibly_unsatisfied_predicates);
+            self.unsatisfied_predicates.borrow_mut().extend(possibly_unsatisfied_predicates);
         }
         None
     }
 
-    fn consider_candidates<'b, ProbesIter>(
+    fn consider_candidates(
         &self,
         self_ty: Ty<'tcx>,
-        probes: ProbesIter,
+        candidates: &[Candidate<'tcx>],
         possibly_unsatisfied_predicates: &mut Vec<(
             ty::Predicate<'tcx>,
             Option<ty::Predicate<'tcx>>,
             Option<ObligationCause<'tcx>>,
         )>,
         mut unstable_candidates: Option<&mut Vec<(Candidate<'tcx>, Symbol)>>,
-    ) -> Option<PickResult<'tcx>>
-    where
-        ProbesIter: Iterator<Item = &'b Candidate<'tcx>> + Clone,
-        'tcx: 'b,
-    {
-        let mut applicable_candidates: Vec<_> = probes
-            .clone()
+    ) -> Option<PickResult<'tcx>> {
+        let mut applicable_candidates: Vec<_> = candidates
+            .iter()
             .map(|probe| {
                 (probe, self.consider_probe(self_ty, probe, possibly_unsatisfied_predicates))
             })
@@ -1306,11 +1308,11 @@ fn consider_candidates<'b, ProbesIter>(
         }
 
         if let Some(uc) = &mut unstable_candidates {
-            applicable_candidates.retain(|&(p, _)| {
+            applicable_candidates.retain(|&(candidate, _)| {
                 if let stability::EvalResult::Deny { feature, .. } =
-                    self.tcx.eval_stability(p.item.def_id, None, self.span, None)
+                    self.tcx.eval_stability(candidate.item.def_id, None, self.span, None)
                 {
-                    uc.push((p.clone(), feature));
+                    uc.push((candidate.clone(), feature));
                     return false;
                 }
                 true
@@ -1318,7 +1320,7 @@ fn consider_candidates<'b, ProbesIter>(
         }
 
         if applicable_candidates.len() > 1 {
-            let sources = probes.map(|p| self.candidate_source(p, self_ty)).collect();
+            let sources = candidates.iter().map(|p| self.candidate_source(p, self_ty)).collect();
             return Some(Err(MethodError::Ambiguity(sources)));
         }
 
@@ -1702,7 +1704,7 @@ fn probe_for_lev_candidate(&mut self) -> Result<Option<ty::AssocItem>, MethodErr
                 self.mode,
                 self.method_name,
                 self.return_type,
-                self.orig_steps_var_values.clone(),
+                &self.orig_steps_var_values,
                 steps,
                 self.scope_expr_id,
             );
@@ -1764,8 +1766,8 @@ fn has_applicable_self(&self, item: &ty::AssocItem) -> bool {
         // -- but this could be overcome.
     }
 
-    fn record_static_candidate(&mut self, source: CandidateSource) {
-        self.static_candidates.push(source);
+    fn record_static_candidate(&self, source: CandidateSource) {
+        self.static_candidates.borrow_mut().push(source);
     }
 
     #[instrument(level = "debug", skip(self))]
@@ -1876,6 +1878,15 @@ fn erase_late_bound_regions<T>(&self, value: ty::Binder<'tcx, T>) -> T
         self.tcx.erase_late_bound_regions(value)
     }
 
+    /// Determine if the given associated item type is relevant in the current context.
+    fn is_relevant_kind_for_mode(&self, kind: ty::AssocKind) -> bool {
+        match (self.mode, kind) {
+            (Mode::MethodCall, ty::AssocKind::Fn) => true,
+            (Mode::Path, ty::AssocKind::Const | ty::AssocKind::Fn) => true,
+            _ => false,
+        }
+    }
+
     /// Finds the method with the appropriate name (or return type, as the case may be). If
     /// `allow_similar_names` is set, find methods with close-matching names.
     // The length of the returned iterator is nearly always 0 or 1 and this
@@ -1888,7 +1899,7 @@ fn erase_late_bound_regions<T>(&self, value: ty::Binder<'tcx, T>) -> T
                     .associated_items(def_id)
                     .in_definition_order()
                     .filter(|x| {
-                        if x.kind.namespace() != Namespace::ValueNS {
+                        if !self.is_relevant_kind_for_mode(x.kind) {
                             return false;
                         }
                         match lev_distance_with_substrings(name.as_str(), x.name.as_str(), max_dist)
@@ -1902,10 +1913,16 @@ fn erase_late_bound_regions<T>(&self, value: ty::Binder<'tcx, T>) -> T
             } else {
                 self.fcx
                     .associated_value(def_id, name)
+                    .filter(|x| self.is_relevant_kind_for_mode(x.kind))
                     .map_or_else(SmallVec::new, |x| SmallVec::from_buf([x]))
             }
         } else {
-            self.tcx.associated_items(def_id).in_definition_order().copied().collect()
+            self.tcx
+                .associated_items(def_id)
+                .in_definition_order()
+                .filter(|x| self.is_relevant_kind_for_mode(x.kind))
+                .copied()
+                .collect()
         }
     }
 }
index 727fab9e7aa1e7df85b4d31bb27ce265d9423b3f..db93cfab2c0dbd6a45508b9c35607b642cfe6c51 100644 (file)
@@ -5,6 +5,7 @@
 use crate::FnCtxt;
 use rustc_ast::ast::Mutability;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_errors::StashKey;
 use rustc_errors::{
     pluralize, struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed,
     MultiSpan,
@@ -13,6 +14,8 @@
 use rustc_hir::def::DefKind;
 use rustc_hir::def_id::DefId;
 use rustc_hir::lang_items::LangItem;
+use rustc_hir::PatKind::Binding;
+use rustc_hir::PathSegment;
 use rustc_hir::{ExprKind, Node, QPath};
 use rustc_infer::infer::{
     type_variable::{TypeVariableOrigin, TypeVariableOriginKind},
     FulfillmentError, Obligation, ObligationCause, ObligationCauseCode,
 };
 
-use std::cmp::Ordering;
-use std::iter;
-
 use super::probe::{AutorefOrPtrAdjustment, IsSuggestion, Mode, ProbeScope};
 use super::{CandidateSource, MethodError, NoMatchData};
+use rustc_hir::intravisit::Visitor;
+use std::cmp::Ordering;
+use std::iter;
 
 impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     fn is_fn_ty(&self, ty: Ty<'tcx>, span: Span) -> bool {
@@ -1462,6 +1465,64 @@ fn suggest_constraining_numerical_ty(
         false
     }
 
+    /// For code `rect::area(...)`,
+    /// if `rect` is a local variable and `area` is a valid assoc method for it,
+    /// we try to suggest `rect.area()`
+    pub(crate) fn suggest_assoc_method_call(&self, segs: &[PathSegment<'_>]) {
+        debug!("suggest_assoc_method_call segs: {:?}", segs);
+        let [seg1, seg2] = segs else { return; };
+        let Some(mut diag) =
+                self.tcx.sess.diagnostic().steal_diagnostic(seg1.ident.span, StashKey::CallAssocMethod)
+                else { return };
+
+        let map = self.infcx.tcx.hir();
+        let body = map.body(rustc_hir::BodyId { hir_id: self.body_id });
+        struct LetVisitor<'a> {
+            result: Option<&'a hir::Expr<'a>>,
+            ident_name: Symbol,
+        }
+
+        // FIXME: This really should be taking scoping, etc into account.
+        impl<'v> Visitor<'v> for LetVisitor<'v> {
+            fn visit_stmt(&mut self, ex: &'v hir::Stmt<'v>) {
+                if let hir::StmtKind::Local(hir::Local { pat, init, .. }) = &ex.kind
+                    && let Binding(_, _, ident, ..) = pat.kind
+                    && ident.name == self.ident_name
+                {
+                    self.result = *init;
+                } else {
+                    hir::intravisit::walk_stmt(self, ex);
+                }
+            }
+        }
+
+        let mut visitor = LetVisitor { result: None, ident_name: seg1.ident.name };
+        visitor.visit_body(&body);
+
+        let parent = self.tcx.hir().get_parent_node(seg1.hir_id);
+        if let Some(Node::Expr(call_expr)) = self.tcx.hir().find(parent)
+            && let Some(expr) = visitor.result
+            && let Some(self_ty) = self.node_ty_opt(expr.hir_id)
+        {
+            let probe = self.lookup_probe(
+                seg2.ident,
+                self_ty,
+                call_expr,
+                ProbeScope::TraitsInScope,
+            );
+            if probe.is_ok() {
+                let sm = self.infcx.tcx.sess.source_map();
+                diag.span_suggestion_verbose(
+                    sm.span_extend_while(seg1.ident.span.shrink_to_hi(), |c| c == ':').unwrap(),
+                    "you may have meant to call an instance method",
+                    ".".to_string(),
+                    Applicability::MaybeIncorrect,
+                );
+            }
+        }
+        diag.emit();
+    }
+
     /// Suggest calling a method on a field i.e. `a.field.bar()` instead of `a.bar()`
     fn suggest_calling_method_on_field(
         &self,
index a8acaf6597aaba3064b261dc005ac964ee241598..d1d328128bc15a145f7b60835cdfe62f7733beae 100644 (file)
@@ -30,8 +30,6 @@
 use rustc_middle::ty::TyCtxt;
 use rustc_span::symbol::{sym, Symbol};
 use rustc_span::Span;
-use std::iter::FromIterator;
-use std::vec::Vec;
 
 const LOADED_FROM_DISK: Symbol = sym::loaded_from_disk;
 const EXCEPT: Symbol = sym::except;
index 58d6e6d7efd69c0d757ff903b4356a586904f7d9..1fd2b9b0d7b7b5a58b4d291cf039575a08715e48 100644 (file)
 use rustc_errors::ErrorGuaranteed;
 use rustc_fs_util::{link_or_copy, LinkOrCopy};
 use rustc_session::{Session, StableCrateId};
+use rustc_span::Symbol;
 
 use std::fs as std_fs;
 use std::io::{self, ErrorKind};
-use std::mem;
 use std::path::{Path, PathBuf};
 use std::time::{Duration, SystemTime, UNIX_EPOCH};
 
@@ -202,7 +202,7 @@ pub fn in_incr_comp_dir(incr_comp_session_dir: &Path, file_name: &str) -> PathBu
 /// [`rustc_interface::queries::dep_graph`]: ../../rustc_interface/struct.Queries.html#structfield.dep_graph
 pub fn prepare_session_directory(
     sess: &Session,
-    crate_name: &str,
+    crate_name: Symbol,
     stable_crate_id: StableCrateId,
 ) -> Result<(), ErrorGuaranteed> {
     if sess.opts.incremental.is_none() {
@@ -304,7 +304,7 @@ pub fn prepare_session_directory(
             }
 
             delete_session_dir_lock_file(sess, &lock_file_path);
-            mem::drop(directory_lock);
+            drop(directory_lock);
         }
     }
 }
@@ -657,7 +657,7 @@ fn string_to_timestamp(s: &str) -> Result<SystemTime, ()> {
     Ok(UNIX_EPOCH + duration)
 }
 
-fn crate_path(sess: &Session, crate_name: &str, stable_crate_id: StableCrateId) -> PathBuf {
+fn crate_path(sess: &Session, crate_name: Symbol, stable_crate_id: StableCrateId) -> PathBuf {
     let incr_dir = sess.opts.incremental.as_ref().unwrap().clone();
 
     let stable_crate_id = base_n::encode(stable_crate_id.to_u64() as u128, INT_ENCODE_BASE);
@@ -863,7 +863,7 @@ pub fn garbage_collect_session_directories(sess: &Session) -> io::Result<()> {
 
                     // Let's make it explicit that the file lock is released at this point,
                     // or rather, that we held on to it until here
-                    mem::drop(lock);
+                    drop(lock);
                 }
                 Err(_) => {
                     debug!(
@@ -897,7 +897,7 @@ pub fn garbage_collect_session_directories(sess: &Session) -> io::Result<()> {
 
         // Let's make it explicit that the file lock is released at this point,
         // or rather, that we held on to it until here
-        mem::drop(lock);
+        drop(lock);
     }
 
     Ok(())
index 39aa27a23c1d2ceeb62825d123893566f57729be..c18a911b2fbcd4db06dfe417f9efbfee8579a4a2 100644 (file)
@@ -4,7 +4,6 @@
 use std::fmt;
 use std::fmt::Debug;
 use std::hash::Hash;
-use std::iter::FromIterator;
 use std::marker::PhantomData;
 use std::ops::{Index, IndexMut, RangeBounds};
 use std::slice;
index 2483ab724a4e32142a0e7078f1a277d22ba38131..4429e4f43629a885543c06a5ac61426e96825760 100644 (file)
@@ -77,10 +77,6 @@ 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()),
             intercrate: self.intercrate,
         }
     }
index e2be8fb12d0d0d976c877a73a1cde0b18bfdc07c..987559d7e47243ead6b12e2762ae7716b0d41010 100644 (file)
 use crate::traits::error_reporting::report_object_safety_error;
 use crate::traits::{
     IfExpressionCause, MatchExpressionArmCause, ObligationCause, ObligationCauseCode,
-    StatementAsExpression,
 };
 
-use crate::errors::SuggAddLetForLetChains;
-use hir::intravisit::{walk_expr, walk_stmt};
 use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
 use rustc_errors::{pluralize, struct_span_err, Diagnostic, ErrorGuaranteed, IntoDiagnosticArg};
 use rustc_errors::{Applicability, DiagnosticBuilder, DiagnosticStyledString, MultiSpan};
 use rustc_hir as hir;
-use rustc_hir::def::{CtorKind, DefKind};
+use rustc_hir::def::DefKind;
 use rustc_hir::def_id::{DefId, LocalDefId};
-use rustc_hir::intravisit::Visitor;
 use rustc_hir::lang_items::LangItem;
 use rustc_hir::Node;
 use rustc_middle::dep_graph::DepContext;
-use rustc_middle::ty::print::with_no_trimmed_paths;
 use rustc_middle::ty::relate::{self, RelateResult, TypeRelation};
 use rustc_middle::ty::{
     self, error::TypeError, List, Region, Ty, TyCtxt, TypeFoldable, TypeSuperVisitable,
 use rustc_span::{sym, symbol::kw, BytePos, DesugaringKind, Pos, Span};
 use rustc_target::spec::abi;
 use std::ops::{ControlFlow, Deref};
+use std::path::PathBuf;
 use std::{cmp, fmt, iter};
 
 mod note;
+mod suggest;
 
 pub(crate) mod need_type_info;
 pub use need_type_info::TypeAnnotationNeeded;
@@ -95,6 +92,7 @@
 pub struct TypeErrCtxt<'a, 'tcx> {
     pub infcx: &'a InferCtxt<'tcx>,
     pub typeck_results: Option<std::cell::Ref<'a, ty::TypeckResults<'tcx>>>,
+    pub normalize_fn_sig: Box<dyn Fn(ty::PolyFnSig<'tcx>) -> ty::PolyFnSig<'tcx> + 'a>,
     pub fallback_has_occurred: bool,
 }
 
@@ -340,7 +338,15 @@ pub fn unexpected_hidden_region_diagnostic<'tcx>(
 
 impl<'tcx> InferCtxt<'tcx> {
     pub fn get_impl_future_output_ty(&self, ty: Ty<'tcx>) -> Option<Ty<'tcx>> {
-        let ty::Opaque(def_id, substs) = *ty.kind() else { return None; };
+        let (def_id, substs) = match *ty.kind() {
+            ty::Opaque(def_id, substs) => (def_id, substs),
+            ty::Projection(data)
+                if self.tcx.def_kind(data.item_def_id) == DefKind::ImplTraitPlaceholder =>
+            {
+                (data.item_def_id, data.substs)
+            }
+            _ => return None,
+        };
 
         let future_trait = self.tcx.require_lang_item(LangItem::Future, None);
         let item_def_id = self.tcx.associated_item_def_ids(future_trait)[0];
@@ -797,87 +803,6 @@ fn note_error_origin(
         }
     }
 
-    fn suggest_remove_semi_or_return_binding(
-        &self,
-        err: &mut Diagnostic,
-        first_id: Option<hir::HirId>,
-        first_ty: Ty<'tcx>,
-        first_span: Span,
-        second_id: Option<hir::HirId>,
-        second_ty: Ty<'tcx>,
-        second_span: Span,
-    ) {
-        let remove_semicolon = [
-            (first_id, self.resolve_vars_if_possible(second_ty)),
-            (second_id, self.resolve_vars_if_possible(first_ty)),
-        ]
-        .into_iter()
-        .find_map(|(id, ty)| {
-            let hir::Node::Block(blk) = self.tcx.hir().get(id?) else { return None };
-            self.could_remove_semicolon(blk, ty)
-        });
-        match remove_semicolon {
-            Some((sp, StatementAsExpression::NeedsBoxing)) => {
-                err.multipart_suggestion(
-                    "consider removing this semicolon and boxing the expressions",
-                    vec![
-                        (first_span.shrink_to_lo(), "Box::new(".to_string()),
-                        (first_span.shrink_to_hi(), ")".to_string()),
-                        (second_span.shrink_to_lo(), "Box::new(".to_string()),
-                        (second_span.shrink_to_hi(), ")".to_string()),
-                        (sp, String::new()),
-                    ],
-                    Applicability::MachineApplicable,
-                );
-            }
-            Some((sp, StatementAsExpression::CorrectType)) => {
-                err.span_suggestion_short(
-                    sp,
-                    "consider removing this semicolon",
-                    "",
-                    Applicability::MachineApplicable,
-                );
-            }
-            None => {
-                for (id, ty) in [(first_id, second_ty), (second_id, first_ty)] {
-                    if let Some(id) = id
-                        && let hir::Node::Block(blk) = self.tcx.hir().get(id)
-                        && self.consider_returning_binding(blk, ty, err)
-                    {
-                        break;
-                    }
-                }
-            }
-        }
-    }
-
-    fn suggest_boxing_for_return_impl_trait(
-        &self,
-        err: &mut Diagnostic,
-        return_sp: Span,
-        arm_spans: impl Iterator<Item = Span>,
-    ) {
-        err.multipart_suggestion(
-            "you could change the return type to be a boxed trait object",
-            vec![
-                (return_sp.with_hi(return_sp.lo() + BytePos(4)), "Box<dyn".to_string()),
-                (return_sp.shrink_to_hi(), ">".to_string()),
-            ],
-            Applicability::MaybeIncorrect,
-        );
-        let sugg = arm_spans
-            .flat_map(|sp| {
-                [(sp.shrink_to_lo(), "Box::new(".to_string()), (sp.shrink_to_hi(), ")".to_string())]
-                    .into_iter()
-            })
-            .collect::<Vec<_>>();
-        err.multipart_suggestion(
-            "if you change the return type to expect trait objects, box the returned expressions",
-            sugg,
-            Applicability::MaybeIncorrect,
-        );
-    }
-
     /// Given that `other_ty` is the same as a type argument for `name` in `sub`, populate `value`
     /// highlighting `name` and every type argument that isn't at `pos` (which is `other_ty`), and
     /// populate `other_value` with `other_ty`.
@@ -1007,22 +932,14 @@ 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 sig1 = &(self.normalize_fn_sig)(*sig1);
+        let sig2 = &(self.normalize_fn_sig)(*sig2);
 
         let get_lifetimes = |sig| {
             use rustc_hir::def::Namespace;
@@ -1262,7 +1179,7 @@ fn lifetime_display(lifetime: Region<'_>) -> String {
                     let num_display_types = consts_offset - regions_len;
                     for (i, (ta1, ta2)) in type_arguments.take(num_display_types).enumerate() {
                         let i = i + regions_len;
-                        if ta1 == ta2 {
+                        if ta1 == ta2 && !self.tcx.sess.verbose() {
                             values.0.push_normal("_");
                             values.1.push_normal("_");
                         } else {
@@ -1278,7 +1195,7 @@ fn lifetime_display(lifetime: Region<'_>) -> String {
                     let const_arguments = sub1.consts().zip(sub2.consts());
                     for (i, (ca1, ca2)) in const_arguments.enumerate() {
                         let i = i + consts_offset;
-                        if ca1 == ca2 {
+                        if ca1 == ca2 && !self.tcx.sess.verbose() {
                             values.0.push_normal("_");
                             values.1.push_normal("_");
                         } else {
@@ -1351,10 +1268,7 @@ fn lifetime_display(lifetime: Region<'_>) -> String {
                             .map(|(mod_str, _)| mod_str.len() + separator_len)
                             .sum();
 
-                    debug!(
-                        "cmp: separator_len={}, split_idx={}, min_len={}",
-                        separator_len, split_idx, min_len
-                    );
+                    debug!(?separator_len, ?split_idx, ?min_len, "cmp");
 
                     if split_idx >= min_len {
                         // paths are identical, highlight everything
@@ -1365,7 +1279,7 @@ fn lifetime_display(lifetime: Region<'_>) -> String {
                     } else {
                         let (common, uniq1) = t1_str.split_at(split_idx);
                         let (_, uniq2) = t2_str.split_at(split_idx);
-                        debug!("cmp: common={}, uniq1={}, uniq2={}", common, uniq1, uniq2);
+                        debug!(?common, ?uniq1, ?uniq2, "cmp");
 
                         values.0.push_normal(common);
                         values.0.push_highlighted(uniq1);
@@ -1457,7 +1371,7 @@ fn lifetime_display(lifetime: Region<'_>) -> String {
             (ty::FnPtr(sig1), ty::FnPtr(sig2)) => self.cmp_fn_sig(sig1, sig2),
 
             _ => {
-                if t1 == t2 {
+                if t1 == t2 && !self.tcx.sess.verbose() {
                     // The two types are the same, elide and don't highlight.
                     (DiagnosticStyledString::normal("_"), DiagnosticStyledString::normal("_"))
                 } else {
@@ -1658,17 +1572,14 @@ enum Mismatch<'a> {
                     }
                     ValuePairs::Regions(_) => (false, Mismatch::Fixed("lifetime")),
                 };
-                let vals = match self.values_str(values) {
-                    Some((expected, found)) => Some((expected, found)),
-                    None => {
-                        // Derived error. Cancel the emitter.
-                        // NOTE(eddyb) this was `.cancel()`, but `diag`
-                        // is borrowed, so we can't fully defuse it.
-                        diag.downgrade_to_delayed_bug();
-                        return;
-                    }
+                let Some(vals) = self.values_str(values) else {
+                    // Derived error. Cancel the emitter.
+                    // NOTE(eddyb) this was `.cancel()`, but `diag`
+                    // is borrowed, so we can't fully defuse it.
+                    diag.downgrade_to_delayed_bug();
+                    return;
                 };
-                (vals, exp_found, is_simple_error, Some(values))
+                (Some(vals), exp_found, is_simple_error, Some(values))
             }
         };
 
@@ -1700,7 +1611,7 @@ enum Mismatch<'a> {
             label_or_note(span, &terr.to_string());
         }
 
-        if let Some((expected, found)) = expected_found {
+        if let Some((expected, found, exp_p, found_p)) = expected_found {
             let (expected_label, found_label, exp_found) = match exp_found {
                 Mismatch::Variable(ef) => (
                     ef.expected.prefix_string(self.tcx),
@@ -1817,32 +1728,41 @@ enum Similar<'tcx> {
                 }
                 TypeError::Sorts(values) => {
                     let extra = expected == found;
-                    let sort_string = |ty: Ty<'tcx>| match (extra, ty.kind()) {
-                        (true, ty::Opaque(def_id, _)) => {
-                            let sm = self.tcx.sess.source_map();
-                            let pos = sm.lookup_char_pos(self.tcx.def_span(*def_id).lo());
-                            format!(
-                                " (opaque type at <{}:{}:{}>)",
-                                sm.filename_for_diagnostics(&pos.file.name),
-                                pos.line,
-                                pos.col.to_usize() + 1,
-                            )
-                        }
-                        (true, ty::Projection(proj))
-                            if self.tcx.def_kind(proj.item_def_id)
-                                == DefKind::ImplTraitPlaceholder =>
-                        {
-                            let sm = self.tcx.sess.source_map();
-                            let pos = sm.lookup_char_pos(self.tcx.def_span(proj.item_def_id).lo());
-                            format!(
-                                " (trait associated opaque type at <{}:{}:{}>)",
-                                sm.filename_for_diagnostics(&pos.file.name),
-                                pos.line,
-                                pos.col.to_usize() + 1,
-                            )
+                    let sort_string = |ty: Ty<'tcx>, path: Option<PathBuf>| {
+                        let mut s = match (extra, ty.kind()) {
+                            (true, ty::Opaque(def_id, _)) => {
+                                let sm = self.tcx.sess.source_map();
+                                let pos = sm.lookup_char_pos(self.tcx.def_span(*def_id).lo());
+                                format!(
+                                    " (opaque type at <{}:{}:{}>)",
+                                    sm.filename_for_diagnostics(&pos.file.name),
+                                    pos.line,
+                                    pos.col.to_usize() + 1,
+                                )
+                            }
+                            (true, ty::Projection(proj))
+                                if self.tcx.def_kind(proj.item_def_id)
+                                    == DefKind::ImplTraitPlaceholder =>
+                            {
+                                let sm = self.tcx.sess.source_map();
+                                let pos = sm.lookup_char_pos(self.tcx.def_span(proj.item_def_id).lo());
+                                format!(
+                                    " (trait associated opaque type at <{}:{}:{}>)",
+                                    sm.filename_for_diagnostics(&pos.file.name),
+                                    pos.line,
+                                    pos.col.to_usize() + 1,
+                                )
+                            }
+                            (true, _) => format!(" ({})", ty.sort_string(self.tcx)),
+                            (false, _) => "".to_string(),
+                        };
+                        if let Some(path) = path {
+                            s.push_str(&format!(
+                                "\nthe full type name has been written to '{}'",
+                                path.display(),
+                            ));
                         }
-                        (true, _) => format!(" ({})", ty.sort_string(self.tcx)),
-                        (false, _) => "".to_string(),
+                        s
                     };
                     if !(values.expected.is_simple_text() && values.found.is_simple_text())
                         || (exp_found.map_or(false, |ef| {
@@ -1864,8 +1784,8 @@ enum Similar<'tcx> {
                             expected,
                             &found_label,
                             found,
-                            &sort_string(values.expected),
-                            &sort_string(values.found),
+                            &sort_string(values.expected, exp_p),
+                            &sort_string(values.found, found_p),
                         );
                     }
                 }
@@ -1939,310 +1859,6 @@ enum Similar<'tcx> {
         debug!(?diag);
     }
 
-    fn suggest_tuple_pattern(
-        &self,
-        cause: &ObligationCause<'tcx>,
-        exp_found: &ty::error::ExpectedFound<Ty<'tcx>>,
-        diag: &mut Diagnostic,
-    ) {
-        // Heavily inspired by `FnCtxt::suggest_compatible_variants`, with
-        // some modifications due to that being in typeck and this being in infer.
-        if let ObligationCauseCode::Pattern { .. } = cause.code() {
-            if let ty::Adt(expected_adt, substs) = exp_found.expected.kind() {
-                let compatible_variants: Vec<_> = expected_adt
-                    .variants()
-                    .iter()
-                    .filter(|variant| {
-                        variant.fields.len() == 1 && variant.ctor_kind() == Some(CtorKind::Fn)
-                    })
-                    .filter_map(|variant| {
-                        let sole_field = &variant.fields[0];
-                        let sole_field_ty = sole_field.ty(self.tcx, substs);
-                        if self.same_type_modulo_infer(sole_field_ty, exp_found.found) {
-                            let variant_path =
-                                with_no_trimmed_paths!(self.tcx.def_path_str(variant.def_id));
-                            // FIXME #56861: DRYer prelude filtering
-                            if let Some(path) = variant_path.strip_prefix("std::prelude::") {
-                                if let Some((_, path)) = path.split_once("::") {
-                                    return Some(path.to_string());
-                                }
-                            }
-                            Some(variant_path)
-                        } else {
-                            None
-                        }
-                    })
-                    .collect();
-                match &compatible_variants[..] {
-                    [] => {}
-                    [variant] => {
-                        diag.multipart_suggestion_verbose(
-                            &format!("try wrapping the pattern in `{}`", variant),
-                            vec![
-                                (cause.span.shrink_to_lo(), format!("{}(", variant)),
-                                (cause.span.shrink_to_hi(), ")".to_string()),
-                            ],
-                            Applicability::MaybeIncorrect,
-                        );
-                    }
-                    _ => {
-                        // More than one matching variant.
-                        diag.multipart_suggestions(
-                            &format!(
-                                "try wrapping the pattern in a variant of `{}`",
-                                self.tcx.def_path_str(expected_adt.did())
-                            ),
-                            compatible_variants.into_iter().map(|variant| {
-                                vec![
-                                    (cause.span.shrink_to_lo(), format!("{}(", variant)),
-                                    (cause.span.shrink_to_hi(), ")".to_string()),
-                                ]
-                            }),
-                            Applicability::MaybeIncorrect,
-                        );
-                    }
-                }
-            }
-        }
-    }
-
-    /// A possible error is to forget to add `.await` when using futures:
-    ///
-    /// ```compile_fail,E0308
-    /// async fn make_u32() -> u32 {
-    ///     22
-    /// }
-    ///
-    /// fn take_u32(x: u32) {}
-    ///
-    /// async fn foo() {
-    ///     let x = make_u32();
-    ///     take_u32(x);
-    /// }
-    /// ```
-    ///
-    /// This routine checks if the found type `T` implements `Future<Output=U>` where `U` is the
-    /// expected type. If this is the case, and we are inside of an async body, it suggests adding
-    /// `.await` to the tail of the expression.
-    fn suggest_await_on_expect_found(
-        &self,
-        cause: &ObligationCause<'tcx>,
-        exp_span: Span,
-        exp_found: &ty::error::ExpectedFound<Ty<'tcx>>,
-        diag: &mut Diagnostic,
-    ) {
-        debug!(
-            "suggest_await_on_expect_found: exp_span={:?}, expected_ty={:?}, found_ty={:?}",
-            exp_span, exp_found.expected, exp_found.found,
-        );
-
-        if let ObligationCauseCode::CompareImplItemObligation { .. } = cause.code() {
-            return;
-        }
-
-        match (
-            self.get_impl_future_output_ty(exp_found.expected),
-            self.get_impl_future_output_ty(exp_found.found),
-        ) {
-            (Some(exp), Some(found)) if self.same_type_modulo_infer(exp, found) => match cause
-                .code()
-            {
-                ObligationCauseCode::IfExpression(box IfExpressionCause { then_id, .. }) => {
-                    let then_span = self.find_block_span_from_hir_id(*then_id);
-                    diag.multipart_suggestion(
-                        "consider `await`ing on both `Future`s",
-                        vec![
-                            (then_span.shrink_to_hi(), ".await".to_string()),
-                            (exp_span.shrink_to_hi(), ".await".to_string()),
-                        ],
-                        Applicability::MaybeIncorrect,
-                    );
-                }
-                ObligationCauseCode::MatchExpressionArm(box MatchExpressionArmCause {
-                    prior_arms,
-                    ..
-                }) => {
-                    if let [.., arm_span] = &prior_arms[..] {
-                        diag.multipart_suggestion(
-                            "consider `await`ing on both `Future`s",
-                            vec![
-                                (arm_span.shrink_to_hi(), ".await".to_string()),
-                                (exp_span.shrink_to_hi(), ".await".to_string()),
-                            ],
-                            Applicability::MaybeIncorrect,
-                        );
-                    } else {
-                        diag.help("consider `await`ing on both `Future`s");
-                    }
-                }
-                _ => {
-                    diag.help("consider `await`ing on both `Future`s");
-                }
-            },
-            (_, Some(ty)) if self.same_type_modulo_infer(exp_found.expected, ty) => {
-                diag.span_suggestion_verbose(
-                    exp_span.shrink_to_hi(),
-                    "consider `await`ing on the `Future`",
-                    ".await",
-                    Applicability::MaybeIncorrect,
-                );
-            }
-            (Some(ty), _) if self.same_type_modulo_infer(ty, exp_found.found) => match cause.code()
-            {
-                ObligationCauseCode::Pattern { span: Some(then_span), .. } => {
-                    diag.span_suggestion_verbose(
-                        then_span.shrink_to_hi(),
-                        "consider `await`ing on the `Future`",
-                        ".await",
-                        Applicability::MaybeIncorrect,
-                    );
-                }
-                ObligationCauseCode::IfExpression(box IfExpressionCause { then_id, .. }) => {
-                    let then_span = self.find_block_span_from_hir_id(*then_id);
-                    diag.span_suggestion_verbose(
-                        then_span.shrink_to_hi(),
-                        "consider `await`ing on the `Future`",
-                        ".await",
-                        Applicability::MaybeIncorrect,
-                    );
-                }
-                ObligationCauseCode::MatchExpressionArm(box MatchExpressionArmCause {
-                    ref prior_arms,
-                    ..
-                }) => {
-                    diag.multipart_suggestion_verbose(
-                        "consider `await`ing on the `Future`",
-                        prior_arms
-                            .iter()
-                            .map(|arm| (arm.shrink_to_hi(), ".await".to_string()))
-                            .collect(),
-                        Applicability::MaybeIncorrect,
-                    );
-                }
-                _ => {}
-            },
-            _ => {}
-        }
-    }
-
-    fn suggest_accessing_field_where_appropriate(
-        &self,
-        cause: &ObligationCause<'tcx>,
-        exp_found: &ty::error::ExpectedFound<Ty<'tcx>>,
-        diag: &mut Diagnostic,
-    ) {
-        debug!(
-            "suggest_accessing_field_where_appropriate(cause={:?}, exp_found={:?})",
-            cause, exp_found
-        );
-        if let ty::Adt(expected_def, expected_substs) = exp_found.expected.kind() {
-            if expected_def.is_enum() {
-                return;
-            }
-
-            if let Some((name, ty)) = expected_def
-                .non_enum_variant()
-                .fields
-                .iter()
-                .filter(|field| field.vis.is_accessible_from(field.did, self.tcx))
-                .map(|field| (field.name, field.ty(self.tcx, expected_substs)))
-                .find(|(_, ty)| self.same_type_modulo_infer(*ty, exp_found.found))
-            {
-                if let ObligationCauseCode::Pattern { span: Some(span), .. } = *cause.code() {
-                    if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) {
-                        let suggestion = if expected_def.is_struct() {
-                            format!("{}.{}", snippet, name)
-                        } else if expected_def.is_union() {
-                            format!("unsafe {{ {}.{} }}", snippet, name)
-                        } else {
-                            return;
-                        };
-                        diag.span_suggestion(
-                            span,
-                            &format!(
-                                "you might have meant to use field `{}` whose type is `{}`",
-                                name, ty
-                            ),
-                            suggestion,
-                            Applicability::MaybeIncorrect,
-                        );
-                    }
-                }
-            }
-        }
-    }
-
-    /// When encountering a case where `.as_ref()` on a `Result` or `Option` would be appropriate,
-    /// suggests it.
-    fn suggest_as_ref_where_appropriate(
-        &self,
-        span: Span,
-        exp_found: &ty::error::ExpectedFound<Ty<'tcx>>,
-        diag: &mut Diagnostic,
-    ) {
-        if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span)
-            && let Some(msg) = self.should_suggest_as_ref(exp_found.expected, exp_found.found)
-        {
-            diag.span_suggestion(
-                span,
-                msg,
-                // HACK: fix issue# 100605, suggesting convert from &Option<T> to Option<&T>, remove the extra `&`
-                format!("{}.as_ref()", snippet.trim_start_matches('&')),
-                Applicability::MachineApplicable,
-            );
-        }
-    }
-
-    pub fn should_suggest_as_ref(&self, expected: Ty<'tcx>, found: Ty<'tcx>) -> Option<&str> {
-        if let (ty::Adt(exp_def, exp_substs), ty::Ref(_, found_ty, _)) =
-            (expected.kind(), found.kind())
-        {
-            if let ty::Adt(found_def, found_substs) = *found_ty.kind() {
-                if exp_def == &found_def {
-                    let have_as_ref = &[
-                        (
-                            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(|(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())
-                        {
-                            match *exp_ty.kind() {
-                                ty::Ref(_, exp_ty, _) => {
-                                    match (exp_ty.kind(), found_ty.kind()) {
-                                        (_, ty::Param(_))
-                                        | (_, ty::Infer(_))
-                                        | (ty::Param(_), _)
-                                        | (ty::Infer(_), _) => {}
-                                        _ if self.same_type_modulo_infer(exp_ty, found_ty) => {}
-                                        _ => show_suggestion = false,
-                                    };
-                                }
-                                ty::Param(_) | ty::Infer(_) => {}
-                                _ => show_suggestion = false,
-                            }
-                        }
-                        if show_suggestion {
-                            return Some(*msg);
-                        }
-                    }
-                }
-            }
-        }
-        None
-    }
-
     pub fn report_and_explain_type_error(
         &self,
         trace: TypeTrace<'tcx>,
@@ -2338,7 +1954,7 @@ fn escape_literal(s: &str) -> String {
                 let code = trace.cause.code();
                 if let &MatchExpressionArm(box MatchExpressionArmCause { source, .. }) = code
                     && let hir::MatchSource::TryDesugar = source
-                    && let Some((expected_ty, found_ty)) = self.values_str(trace.values)
+                    && let Some((expected_ty, found_ty, _, _)) = self.values_str(trace.values)
                 {
                     err.note(&format!(
                         "`?` operator cannot convert from `{}` to `{}`",
@@ -2356,67 +1972,6 @@ fn escape_literal(s: &str) -> String {
         diag
     }
 
-    /// Try to find code with pattern `if Some(..) = expr`
-    /// use a `visitor` to mark the `if` which its span contains given error span,
-    /// and then try to find a assignment in the `cond` part, which span is equal with error span
-    fn suggest_let_for_letchains(
-        &self,
-        err: &mut Diagnostic,
-        cause: &ObligationCause<'_>,
-        span: Span,
-    ) {
-        let hir = self.tcx.hir();
-        let fn_hir_id = hir.get_parent_node(cause.body_id);
-        if let Some(node) = self.tcx.hir().find(fn_hir_id) &&
-            let hir::Node::Item(hir::Item {
-                    kind: hir::ItemKind::Fn(_sig, _, body_id), ..
-                }) = node {
-        let body = hir.body(*body_id);
-
-        /// Find the if expression with given span
-        struct IfVisitor {
-            pub result: bool,
-            pub found_if: bool,
-            pub err_span: Span,
-        }
-
-        impl<'v> Visitor<'v> for IfVisitor {
-            fn visit_expr(&mut self, ex: &'v hir::Expr<'v>) {
-                if self.result { return; }
-                match ex.kind {
-                    hir::ExprKind::If(cond, _, _) => {
-                        self.found_if = true;
-                        walk_expr(self, cond);
-                        self.found_if = false;
-                    }
-                    _ => walk_expr(self, ex),
-                }
-            }
-
-            fn visit_stmt(&mut self, ex: &'v hir::Stmt<'v>) {
-                if let hir::StmtKind::Local(hir::Local {
-                        span, pat: hir::Pat{..}, ty: None, init: Some(_), ..
-                    }) = &ex.kind
-                    && self.found_if
-                    && span.eq(&self.err_span) {
-                        self.result = true;
-                }
-                walk_stmt(self, ex);
-            }
-
-            fn visit_body(&mut self, body: &'v hir::Body<'v>) {
-                hir::intravisit::walk_body(self, body);
-            }
-        }
-
-        let mut visitor = IfVisitor { err_span: span, found_if: false, result: false };
-        visitor.visit_body(&body);
-        if visitor.result {
-                err.subdiagnostic(SuggAddLetForLetChains{span: span.shrink_to_lo()});
-            }
-        }
-    }
-
     fn emit_tuple_wrap_err(
         &self,
         err: &mut Diagnostic,
@@ -2454,7 +2009,8 @@ fn emit_tuple_wrap_err(
     fn values_str(
         &self,
         values: ValuePairs<'tcx>,
-    ) -> Option<(DiagnosticStyledString, DiagnosticStyledString)> {
+    ) -> Option<(DiagnosticStyledString, DiagnosticStyledString, Option<PathBuf>, Option<PathBuf>)>
+    {
         match values {
             infer::Regions(exp_found) => self.expected_found_str(exp_found),
             infer::Terms(exp_found) => self.expected_found_str_term(exp_found),
@@ -2464,7 +2020,7 @@ fn values_str(
                     found: exp_found.found.print_only_trait_path(),
                 };
                 match self.expected_found_str(pretty_exp_found) {
-                    Some((expected, found)) if expected == found => {
+                    Some((expected, found, _, _)) if expected == found => {
                         self.expected_found_str(exp_found)
                     }
                     ret => ret,
@@ -2476,7 +2032,7 @@ fn values_str(
                     found: exp_found.found.print_only_trait_path(),
                 };
                 match self.expected_found_str(pretty_exp_found) {
-                    Some((expected, found)) if expected == found => {
+                    Some((expected, found, _, _)) if expected == found => {
                         self.expected_found_str(exp_found)
                     }
                     ret => ret,
@@ -2488,17 +2044,41 @@ fn values_str(
     fn expected_found_str_term(
         &self,
         exp_found: ty::error::ExpectedFound<ty::Term<'tcx>>,
-    ) -> Option<(DiagnosticStyledString, DiagnosticStyledString)> {
+    ) -> Option<(DiagnosticStyledString, DiagnosticStyledString, Option<PathBuf>, Option<PathBuf>)>
+    {
         let exp_found = self.resolve_vars_if_possible(exp_found);
         if exp_found.references_error() {
             return None;
         }
 
         Some(match (exp_found.expected.unpack(), exp_found.found.unpack()) {
-            (ty::TermKind::Ty(expected), ty::TermKind::Ty(found)) => self.cmp(expected, found),
+            (ty::TermKind::Ty(expected), ty::TermKind::Ty(found)) => {
+                let (mut exp, mut fnd) = self.cmp(expected, found);
+                // Use the terminal width as the basis to determine when to compress the printed
+                // out type, but give ourselves some leeway to avoid ending up creating a file for
+                // a type that is somewhat shorter than the path we'd write to.
+                let len = self.tcx.sess().diagnostic_width() + 40;
+                let exp_s = exp.content();
+                let fnd_s = fnd.content();
+                let mut exp_p = None;
+                let mut fnd_p = None;
+                if exp_s.len() > len {
+                    let (exp_s, exp_path) = self.tcx.short_ty_string(expected);
+                    exp = DiagnosticStyledString::highlighted(exp_s);
+                    exp_p = exp_path;
+                }
+                if fnd_s.len() > len {
+                    let (fnd_s, fnd_path) = self.tcx.short_ty_string(found);
+                    fnd = DiagnosticStyledString::highlighted(fnd_s);
+                    fnd_p = fnd_path;
+                }
+                (exp, fnd, exp_p, fnd_p)
+            }
             _ => (
                 DiagnosticStyledString::highlighted(exp_found.expected.to_string()),
                 DiagnosticStyledString::highlighted(exp_found.found.to_string()),
+                None,
+                None,
             ),
         })
     }
@@ -2507,7 +2087,8 @@ fn expected_found_str_term(
     fn expected_found_str<T: fmt::Display + TypeFoldable<'tcx>>(
         &self,
         exp_found: ty::error::ExpectedFound<T>,
-    ) -> Option<(DiagnosticStyledString, DiagnosticStyledString)> {
+    ) -> Option<(DiagnosticStyledString, DiagnosticStyledString, Option<PathBuf>, Option<PathBuf>)>
+    {
         let exp_found = self.resolve_vars_if_possible(exp_found);
         if exp_found.references_error() {
             return None;
@@ -2516,6 +2097,8 @@ fn expected_found_str<T: fmt::Display + TypeFoldable<'tcx>>(
         Some((
             DiagnosticStyledString::highlighted(exp_found.expected.to_string()),
             DiagnosticStyledString::highlighted(exp_found.found.to_string()),
+            None,
+            None,
         ))
     }
 
@@ -2849,36 +2432,29 @@ fn report_sub_sup_conflict(
         debug!("report_sub_sup_conflict: sup_region={:?}", sup_region);
         debug!("report_sub_sup_conflict: sup_origin={:?}", sup_origin);
 
-        if let (&infer::Subtype(ref sup_trace), &infer::Subtype(ref sub_trace)) =
-            (&sup_origin, &sub_origin)
+        if let infer::Subtype(ref sup_trace) = sup_origin
+            && let infer::Subtype(ref sub_trace) = sub_origin
+            && let Some((sup_expected, sup_found, _, _)) = self.values_str(sup_trace.values)
+            && let Some((sub_expected, sub_found, _, _)) = self.values_str(sub_trace.values)
+            && sub_expected == sup_expected
+            && sub_found == sup_found
         {
-            debug!("report_sub_sup_conflict: sup_trace={:?}", sup_trace);
-            debug!("report_sub_sup_conflict: sub_trace={:?}", sub_trace);
-            debug!("report_sub_sup_conflict: sup_trace.values={:?}", sup_trace.values);
-            debug!("report_sub_sup_conflict: sub_trace.values={:?}", sub_trace.values);
-
-            if let (Some((sup_expected, sup_found)), Some((sub_expected, sub_found))) =
-                (self.values_str(sup_trace.values), self.values_str(sub_trace.values))
-            {
-                if sub_expected == sup_expected && sub_found == sup_found {
-                    note_and_explain_region(
-                        self.tcx,
-                        &mut err,
-                        "...but the lifetime must also be valid for ",
-                        sub_region,
-                        "...",
-                        None,
-                    );
-                    err.span_note(
-                        sup_trace.cause.span,
-                        &format!("...so that the {}", sup_trace.cause.as_requirement_str()),
-                    );
+            note_and_explain_region(
+                self.tcx,
+                &mut err,
+                "...but the lifetime must also be valid for ",
+                sub_region,
+                "...",
+                None,
+            );
+            err.span_note(
+                sup_trace.cause.span,
+                &format!("...so that the {}", sup_trace.cause.as_requirement_str()),
+            );
 
-                    err.note_expected_found(&"", sup_expected, &"", sup_found);
-                    err.emit();
-                    return;
-                }
-            }
+            err.note_expected_found(&"", sup_expected, &"", sup_found);
+            err.emit();
+            return;
         }
 
         self.note_region_origin(&mut err, &sup_origin);
@@ -3227,211 +2803,3 @@ pub fn find_block_span_from_hir_id(&self, hir_id: hir::HirId) -> Span {
         }
     }
 }
-
-impl<'tcx> TypeErrCtxt<'_, 'tcx> {
-    /// Be helpful when the user wrote `{... expr; }` and taking the `;` off
-    /// is enough to fix the error.
-    pub fn could_remove_semicolon(
-        &self,
-        blk: &'tcx hir::Block<'tcx>,
-        expected_ty: Ty<'tcx>,
-    ) -> Option<(Span, StatementAsExpression)> {
-        let blk = blk.innermost_block();
-        // Do not suggest if we have a tail expr.
-        if blk.expr.is_some() {
-            return None;
-        }
-        let last_stmt = blk.stmts.last()?;
-        let hir::StmtKind::Semi(ref last_expr) = last_stmt.kind else {
-            return None;
-        };
-        let last_expr_ty = self.typeck_results.as_ref()?.expr_ty_opt(*last_expr)?;
-        let needs_box = match (last_expr_ty.kind(), expected_ty.kind()) {
-            _ if last_expr_ty.references_error() => return None,
-            _ if self.same_type_modulo_infer(last_expr_ty, expected_ty) => {
-                StatementAsExpression::CorrectType
-            }
-            (ty::Opaque(last_def_id, _), ty::Opaque(exp_def_id, _))
-                if last_def_id == exp_def_id =>
-            {
-                StatementAsExpression::CorrectType
-            }
-            (ty::Opaque(last_def_id, last_bounds), ty::Opaque(exp_def_id, exp_bounds)) => {
-                debug!(
-                    "both opaque, likely future {:?} {:?} {:?} {:?}",
-                    last_def_id, last_bounds, exp_def_id, exp_bounds
-                );
-
-                let last_local_id = last_def_id.as_local()?;
-                let exp_local_id = exp_def_id.as_local()?;
-
-                match (
-                    &self.tcx.hir().expect_item(last_local_id).kind,
-                    &self.tcx.hir().expect_item(exp_local_id).kind,
-                ) {
-                    (
-                        hir::ItemKind::OpaqueTy(hir::OpaqueTy { bounds: last_bounds, .. }),
-                        hir::ItemKind::OpaqueTy(hir::OpaqueTy { bounds: exp_bounds, .. }),
-                    ) if iter::zip(*last_bounds, *exp_bounds).all(|(left, right)| {
-                        match (left, right) {
-                            (
-                                hir::GenericBound::Trait(tl, ml),
-                                hir::GenericBound::Trait(tr, mr),
-                            ) if tl.trait_ref.trait_def_id() == tr.trait_ref.trait_def_id()
-                                && ml == mr =>
-                            {
-                                true
-                            }
-                            (
-                                hir::GenericBound::LangItemTrait(langl, _, _, argsl),
-                                hir::GenericBound::LangItemTrait(langr, _, _, argsr),
-                            ) if langl == langr => {
-                                // FIXME: consider the bounds!
-                                debug!("{:?} {:?}", argsl, argsr);
-                                true
-                            }
-                            _ => false,
-                        }
-                    }) =>
-                    {
-                        StatementAsExpression::NeedsBoxing
-                    }
-                    _ => StatementAsExpression::CorrectType,
-                }
-            }
-            _ => return None,
-        };
-        let span = if last_stmt.span.from_expansion() {
-            let mac_call = rustc_span::source_map::original_sp(last_stmt.span, blk.span);
-            self.tcx.sess.source_map().mac_call_stmt_semi_span(mac_call)?
-        } else {
-            last_stmt.span.with_lo(last_stmt.span.hi() - BytePos(1))
-        };
-        Some((span, needs_box))
-    }
-
-    /// Suggest returning a local binding with a compatible type if the block
-    /// has no return expression.
-    pub fn consider_returning_binding(
-        &self,
-        blk: &'tcx hir::Block<'tcx>,
-        expected_ty: Ty<'tcx>,
-        err: &mut Diagnostic,
-    ) -> bool {
-        let blk = blk.innermost_block();
-        // Do not suggest if we have a tail expr.
-        if blk.expr.is_some() {
-            return false;
-        }
-        let mut shadowed = FxIndexSet::default();
-        let mut candidate_idents = vec![];
-        let mut find_compatible_candidates = |pat: &hir::Pat<'_>| {
-            if let hir::PatKind::Binding(_, hir_id, ident, _) = &pat.kind
-                && let Some(pat_ty) = self
-                    .typeck_results
-                    .as_ref()
-                    .and_then(|typeck_results| typeck_results.node_type_opt(*hir_id))
-            {
-                let pat_ty = self.resolve_vars_if_possible(pat_ty);
-                if self.same_type_modulo_infer(pat_ty, expected_ty)
-                    && !(pat_ty, expected_ty).references_error()
-                    && shadowed.insert(ident.name)
-                {
-                    candidate_idents.push((*ident, pat_ty));
-                }
-            }
-            true
-        };
-
-        let hir = self.tcx.hir();
-        for stmt in blk.stmts.iter().rev() {
-            let hir::StmtKind::Local(local) = &stmt.kind else { continue; };
-            local.pat.walk(&mut find_compatible_candidates);
-        }
-        match hir.find(hir.get_parent_node(blk.hir_id)) {
-            Some(hir::Node::Expr(hir::Expr { hir_id, .. })) => {
-                match hir.find(hir.get_parent_node(*hir_id)) {
-                    Some(hir::Node::Arm(hir::Arm { pat, .. })) => {
-                        pat.walk(&mut find_compatible_candidates);
-                    }
-                    Some(
-                        hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(_, _, body), .. })
-                        | hir::Node::ImplItem(hir::ImplItem {
-                            kind: hir::ImplItemKind::Fn(_, body),
-                            ..
-                        })
-                        | hir::Node::TraitItem(hir::TraitItem {
-                            kind: hir::TraitItemKind::Fn(_, hir::TraitFn::Provided(body)),
-                            ..
-                        })
-                        | hir::Node::Expr(hir::Expr {
-                            kind: hir::ExprKind::Closure(hir::Closure { body, .. }),
-                            ..
-                        }),
-                    ) => {
-                        for param in hir.body(*body).params {
-                            param.pat.walk(&mut find_compatible_candidates);
-                        }
-                    }
-                    Some(hir::Node::Expr(hir::Expr {
-                        kind:
-                            hir::ExprKind::If(
-                                hir::Expr { kind: hir::ExprKind::Let(let_), .. },
-                                then_block,
-                                _,
-                            ),
-                        ..
-                    })) if then_block.hir_id == *hir_id => {
-                        let_.pat.walk(&mut find_compatible_candidates);
-                    }
-                    _ => {}
-                }
-            }
-            _ => {}
-        }
-
-        match &candidate_idents[..] {
-            [(ident, _ty)] => {
-                let sm = self.tcx.sess.source_map();
-                if let Some(stmt) = blk.stmts.last() {
-                    let stmt_span = sm.stmt_span(stmt.span, blk.span);
-                    let sugg = if sm.is_multiline(blk.span)
-                        && let Some(spacing) = sm.indentation_before(stmt_span)
-                    {
-                        format!("\n{spacing}{ident}")
-                    } else {
-                        format!(" {ident}")
-                    };
-                    err.span_suggestion_verbose(
-                        stmt_span.shrink_to_hi(),
-                        format!("consider returning the local binding `{ident}`"),
-                        sugg,
-                        Applicability::MaybeIncorrect,
-                    );
-                } else {
-                    let sugg = if sm.is_multiline(blk.span)
-                        && let Some(spacing) = sm.indentation_before(blk.span.shrink_to_lo())
-                    {
-                        format!("\n{spacing}    {ident}\n{spacing}")
-                    } else {
-                        format!(" {ident} ")
-                    };
-                    let left_span = sm.span_through_char(blk.span, '{').shrink_to_hi();
-                    err.span_suggestion_verbose(
-                        sm.span_extend_while(left_span, |c| c.is_whitespace()).unwrap_or(left_span),
-                        format!("consider returning the local binding `{ident}`"),
-                        sugg,
-                        Applicability::MaybeIncorrect,
-                    );
-                }
-                true
-            }
-            values if (1..3).contains(&values.len()) => {
-                let spans = values.iter().map(|(ident, _)| ident.span).collect::<Vec<_>>();
-                err.span_note(spans, "consider returning one of these bindings");
-                true
-            }
-            _ => false,
-        }
-    }
-}
index 41b115f3377ac879d7287aa3910dcdf492221fc7..d2dffa4a0b78e5ef1d75606e165b0a137fbf87e0 100644 (file)
@@ -16,7 +16,7 @@ pub(super) fn note_region_origin(&self, err: &mut Diagnostic, origin: &Subregion
             infer::Subtype(ref trace) => RegionOriginNote::WithRequirement {
                 span: trace.cause.span,
                 requirement: ObligationCauseAsDiagArg(trace.cause.clone()),
-                expected_found: self.values_str(trace.values),
+                expected_found: self.values_str(trace.values).map(|(e, f, _, _)| (e, f)),
             }
             .add_to_diagnostic(err),
             infer::Reborrow(span) => {
diff --git a/compiler/rustc_infer/src/infer/error_reporting/note_region.rs b/compiler/rustc_infer/src/infer/error_reporting/note_region.rs
new file mode 100644 (file)
index 0000000..41b115f
--- /dev/null
@@ -0,0 +1,427 @@
+use crate::errors::RegionOriginNote;
+use crate::infer::error_reporting::{note_and_explain_region, TypeErrCtxt};
+use crate::infer::{self, SubregionOrigin};
+use rustc_errors::{
+    fluent, struct_span_err, AddToDiagnostic, Diagnostic, DiagnosticBuilder, ErrorGuaranteed,
+};
+use rustc_middle::traits::ObligationCauseCode;
+use rustc_middle::ty::error::TypeError;
+use rustc_middle::ty::{self, Region};
+
+use super::ObligationCauseAsDiagArg;
+
+impl<'tcx> TypeErrCtxt<'_, 'tcx> {
+    pub(super) fn note_region_origin(&self, err: &mut Diagnostic, origin: &SubregionOrigin<'tcx>) {
+        match *origin {
+            infer::Subtype(ref trace) => RegionOriginNote::WithRequirement {
+                span: trace.cause.span,
+                requirement: ObligationCauseAsDiagArg(trace.cause.clone()),
+                expected_found: self.values_str(trace.values),
+            }
+            .add_to_diagnostic(err),
+            infer::Reborrow(span) => {
+                RegionOriginNote::Plain { span, msg: fluent::infer_reborrow }.add_to_diagnostic(err)
+            }
+            infer::ReborrowUpvar(span, ref upvar_id) => {
+                let var_name = self.tcx.hir().name(upvar_id.var_path.hir_id);
+                RegionOriginNote::WithName {
+                    span,
+                    msg: fluent::infer_reborrow,
+                    name: &var_name.to_string(),
+                    continues: false,
+                }
+                .add_to_diagnostic(err);
+            }
+            infer::RelateObjectBound(span) => {
+                RegionOriginNote::Plain { span, msg: fluent::infer_relate_object_bound }
+                    .add_to_diagnostic(err);
+            }
+            infer::DataBorrowed(ty, span) => {
+                RegionOriginNote::WithName {
+                    span,
+                    msg: fluent::infer_data_borrowed,
+                    name: &self.ty_to_string(ty),
+                    continues: false,
+                }
+                .add_to_diagnostic(err);
+            }
+            infer::ReferenceOutlivesReferent(ty, span) => {
+                RegionOriginNote::WithName {
+                    span,
+                    msg: fluent::infer_reference_outlives_referent,
+                    name: &self.ty_to_string(ty),
+                    continues: false,
+                }
+                .add_to_diagnostic(err);
+            }
+            infer::RelateParamBound(span, ty, opt_span) => {
+                RegionOriginNote::WithName {
+                    span,
+                    msg: fluent::infer_relate_param_bound,
+                    name: &self.ty_to_string(ty),
+                    continues: opt_span.is_some(),
+                }
+                .add_to_diagnostic(err);
+                if let Some(span) = opt_span {
+                    RegionOriginNote::Plain { span, msg: fluent::infer_relate_param_bound_2 }
+                        .add_to_diagnostic(err);
+                }
+            }
+            infer::RelateRegionParamBound(span) => {
+                RegionOriginNote::Plain { span, msg: fluent::infer_relate_region_param_bound }
+                    .add_to_diagnostic(err);
+            }
+            infer::CompareImplItemObligation { span, .. } => {
+                RegionOriginNote::Plain { span, msg: fluent::infer_compare_impl_item_obligation }
+                    .add_to_diagnostic(err);
+            }
+            infer::CheckAssociatedTypeBounds { ref parent, .. } => {
+                self.note_region_origin(err, &parent);
+            }
+            infer::AscribeUserTypeProvePredicate(span) => {
+                RegionOriginNote::Plain {
+                    span,
+                    msg: fluent::infer_ascribe_user_type_prove_predicate,
+                }
+                .add_to_diagnostic(err);
+            }
+        }
+    }
+
+    pub(super) fn report_concrete_failure(
+        &self,
+        origin: SubregionOrigin<'tcx>,
+        sub: Region<'tcx>,
+        sup: Region<'tcx>,
+    ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
+        match origin {
+            infer::Subtype(box trace) => {
+                let terr = TypeError::RegionsDoesNotOutlive(sup, sub);
+                let mut err = self.report_and_explain_type_error(trace, terr);
+                match (*sub, *sup) {
+                    (ty::RePlaceholder(_), ty::RePlaceholder(_)) => {}
+                    (ty::RePlaceholder(_), _) => {
+                        note_and_explain_region(
+                            self.tcx,
+                            &mut err,
+                            "",
+                            sup,
+                            " doesn't meet the lifetime requirements",
+                            None,
+                        );
+                    }
+                    (_, ty::RePlaceholder(_)) => {
+                        note_and_explain_region(
+                            self.tcx,
+                            &mut err,
+                            "the required lifetime does not necessarily outlive ",
+                            sub,
+                            "",
+                            None,
+                        );
+                    }
+                    _ => {
+                        note_and_explain_region(self.tcx, &mut err, "", sup, "...", None);
+                        note_and_explain_region(
+                            self.tcx,
+                            &mut err,
+                            "...does not necessarily outlive ",
+                            sub,
+                            "",
+                            None,
+                        );
+                    }
+                }
+                err
+            }
+            infer::Reborrow(span) => {
+                let mut err = struct_span_err!(
+                    self.tcx.sess,
+                    span,
+                    E0312,
+                    "lifetime of reference outlives lifetime of borrowed content..."
+                );
+                note_and_explain_region(
+                    self.tcx,
+                    &mut err,
+                    "...the reference is valid for ",
+                    sub,
+                    "...",
+                    None,
+                );
+                note_and_explain_region(
+                    self.tcx,
+                    &mut err,
+                    "...but the borrowed content is only valid for ",
+                    sup,
+                    "",
+                    None,
+                );
+                err
+            }
+            infer::ReborrowUpvar(span, ref upvar_id) => {
+                let var_name = self.tcx.hir().name(upvar_id.var_path.hir_id);
+                let mut err = struct_span_err!(
+                    self.tcx.sess,
+                    span,
+                    E0313,
+                    "lifetime of borrowed pointer outlives lifetime of captured variable `{}`...",
+                    var_name
+                );
+                note_and_explain_region(
+                    self.tcx,
+                    &mut err,
+                    "...the borrowed pointer is valid for ",
+                    sub,
+                    "...",
+                    None,
+                );
+                note_and_explain_region(
+                    self.tcx,
+                    &mut err,
+                    &format!("...but `{}` is only valid for ", var_name),
+                    sup,
+                    "",
+                    None,
+                );
+                err
+            }
+            infer::RelateObjectBound(span) => {
+                let mut err = struct_span_err!(
+                    self.tcx.sess,
+                    span,
+                    E0476,
+                    "lifetime of the source pointer does not outlive lifetime bound of the \
+                     object type"
+                );
+                note_and_explain_region(
+                    self.tcx,
+                    &mut err,
+                    "object type is valid for ",
+                    sub,
+                    "",
+                    None,
+                );
+                note_and_explain_region(
+                    self.tcx,
+                    &mut err,
+                    "source pointer is only valid for ",
+                    sup,
+                    "",
+                    None,
+                );
+                err
+            }
+            infer::RelateParamBound(span, ty, opt_span) => {
+                let mut err = struct_span_err!(
+                    self.tcx.sess,
+                    span,
+                    E0477,
+                    "the type `{}` does not fulfill the required lifetime",
+                    self.ty_to_string(ty)
+                );
+                match *sub {
+                    ty::ReStatic => note_and_explain_region(
+                        self.tcx,
+                        &mut err,
+                        "type must satisfy ",
+                        sub,
+                        if opt_span.is_some() { " as required by this binding" } else { "" },
+                        opt_span,
+                    ),
+                    _ => note_and_explain_region(
+                        self.tcx,
+                        &mut err,
+                        "type must outlive ",
+                        sub,
+                        if opt_span.is_some() { " as required by this binding" } else { "" },
+                        opt_span,
+                    ),
+                }
+                err
+            }
+            infer::RelateRegionParamBound(span) => {
+                let mut err =
+                    struct_span_err!(self.tcx.sess, span, E0478, "lifetime bound not satisfied");
+                note_and_explain_region(
+                    self.tcx,
+                    &mut err,
+                    "lifetime parameter instantiated with ",
+                    sup,
+                    "",
+                    None,
+                );
+                note_and_explain_region(
+                    self.tcx,
+                    &mut err,
+                    "but lifetime parameter must outlive ",
+                    sub,
+                    "",
+                    None,
+                );
+                err
+            }
+            infer::DataBorrowed(ty, span) => {
+                let mut err = struct_span_err!(
+                    self.tcx.sess,
+                    span,
+                    E0490,
+                    "a value of type `{}` is borrowed for too long",
+                    self.ty_to_string(ty)
+                );
+                note_and_explain_region(
+                    self.tcx,
+                    &mut err,
+                    "the type is valid for ",
+                    sub,
+                    "",
+                    None,
+                );
+                note_and_explain_region(
+                    self.tcx,
+                    &mut err,
+                    "but the borrow lasts for ",
+                    sup,
+                    "",
+                    None,
+                );
+                err
+            }
+            infer::ReferenceOutlivesReferent(ty, span) => {
+                let mut err = struct_span_err!(
+                    self.tcx.sess,
+                    span,
+                    E0491,
+                    "in type `{}`, reference has a longer lifetime than the data it references",
+                    self.ty_to_string(ty)
+                );
+                note_and_explain_region(
+                    self.tcx,
+                    &mut err,
+                    "the pointer is valid for ",
+                    sub,
+                    "",
+                    None,
+                );
+                note_and_explain_region(
+                    self.tcx,
+                    &mut err,
+                    "but the referenced data is only valid for ",
+                    sup,
+                    "",
+                    None,
+                );
+                err
+            }
+            infer::CompareImplItemObligation { span, impl_item_def_id, trait_item_def_id } => self
+                .report_extra_impl_obligation(
+                    span,
+                    impl_item_def_id,
+                    trait_item_def_id,
+                    &format!("`{}: {}`", sup, sub),
+                ),
+            infer::CheckAssociatedTypeBounds { impl_item_def_id, trait_item_def_id, parent } => {
+                let mut err = self.report_concrete_failure(*parent, sub, sup);
+
+                let trait_item_span = self.tcx.def_span(trait_item_def_id);
+                let item_name = self.tcx.item_name(impl_item_def_id.to_def_id());
+                err.span_label(
+                    trait_item_span,
+                    format!("definition of `{}` from trait", item_name),
+                );
+
+                let trait_predicates = self.tcx.explicit_predicates_of(trait_item_def_id);
+                let impl_predicates = self.tcx.explicit_predicates_of(impl_item_def_id);
+
+                let impl_predicates: rustc_data_structures::fx::FxHashSet<_> =
+                    impl_predicates.predicates.into_iter().map(|(pred, _)| pred).collect();
+                let clauses: Vec<_> = trait_predicates
+                    .predicates
+                    .into_iter()
+                    .filter(|&(pred, _)| !impl_predicates.contains(pred))
+                    .map(|(pred, _)| format!("{}", pred))
+                    .collect();
+
+                if !clauses.is_empty() {
+                    let generics = self.tcx.hir().get_generics(impl_item_def_id).unwrap();
+                    let where_clause_span = generics.tail_span_for_predicate_suggestion();
+
+                    let suggestion = format!(
+                        "{} {}",
+                        generics.add_where_or_trailing_comma(),
+                        clauses.join(", "),
+                    );
+                    err.span_suggestion(
+                        where_clause_span,
+                        &format!(
+                            "try copying {} from the trait",
+                            if clauses.len() > 1 { "these clauses" } else { "this clause" }
+                        ),
+                        suggestion,
+                        rustc_errors::Applicability::MaybeIncorrect,
+                    );
+                }
+
+                err
+            }
+            infer::AscribeUserTypeProvePredicate(span) => {
+                let mut err =
+                    struct_span_err!(self.tcx.sess, span, E0478, "lifetime bound not satisfied");
+                note_and_explain_region(
+                    self.tcx,
+                    &mut err,
+                    "lifetime instantiated with ",
+                    sup,
+                    "",
+                    None,
+                );
+                note_and_explain_region(
+                    self.tcx,
+                    &mut err,
+                    "but lifetime must outlive ",
+                    sub,
+                    "",
+                    None,
+                );
+                err
+            }
+        }
+    }
+
+    pub(super) fn report_placeholder_failure(
+        &self,
+        placeholder_origin: SubregionOrigin<'tcx>,
+        sub: Region<'tcx>,
+        sup: Region<'tcx>,
+    ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
+        // I can't think how to do better than this right now. -nikomatsakis
+        debug!(?placeholder_origin, ?sub, ?sup, "report_placeholder_failure");
+        match placeholder_origin {
+            infer::Subtype(box ref trace)
+                if matches!(
+                    &trace.cause.code().peel_derives(),
+                    ObligationCauseCode::BindingObligation(..)
+                        | ObligationCauseCode::ExprBindingObligation(..)
+                ) =>
+            {
+                // Hack to get around the borrow checker because trace.cause has an `Rc`.
+                if let ObligationCauseCode::BindingObligation(_, span)
+                | ObligationCauseCode::ExprBindingObligation(_, span, ..) =
+                    &trace.cause.code().peel_derives()
+                {
+                    let span = *span;
+                    let mut err = self.report_concrete_failure(placeholder_origin, sub, sup);
+                    err.span_note(span, "the lifetime requirement is introduced here");
+                    err
+                } else {
+                    unreachable!()
+                }
+            }
+            infer::Subtype(box trace) => {
+                let terr = TypeError::RegionsPlaceholderMismatch;
+                return self.report_and_explain_type_error(trace, terr);
+            }
+            _ => return self.report_concrete_failure(placeholder_origin, sub, sup),
+        }
+    }
+}
diff --git a/compiler/rustc_infer/src/infer/error_reporting/suggest.rs b/compiler/rustc_infer/src/infer/error_reporting/suggest.rs
new file mode 100644 (file)
index 0000000..73b5a2c
--- /dev/null
@@ -0,0 +1,672 @@
+use hir::def::CtorKind;
+use hir::intravisit::{walk_expr, walk_stmt, Visitor};
+use rustc_data_structures::fx::FxIndexSet;
+use rustc_errors::{Applicability, Diagnostic};
+use rustc_hir as hir;
+use rustc_middle::traits::{
+    IfExpressionCause, MatchExpressionArmCause, ObligationCause, ObligationCauseCode,
+    StatementAsExpression,
+};
+use rustc_middle::ty::print::with_no_trimmed_paths;
+use rustc_middle::ty::{self as ty, Ty, TypeVisitable};
+use rustc_span::{sym, BytePos, Span};
+
+use crate::errors::SuggAddLetForLetChains;
+
+use super::TypeErrCtxt;
+
+impl<'tcx> TypeErrCtxt<'_, 'tcx> {
+    pub(super) fn suggest_remove_semi_or_return_binding(
+        &self,
+        err: &mut Diagnostic,
+        first_id: Option<hir::HirId>,
+        first_ty: Ty<'tcx>,
+        first_span: Span,
+        second_id: Option<hir::HirId>,
+        second_ty: Ty<'tcx>,
+        second_span: Span,
+    ) {
+        let remove_semicolon = [
+            (first_id, self.resolve_vars_if_possible(second_ty)),
+            (second_id, self.resolve_vars_if_possible(first_ty)),
+        ]
+        .into_iter()
+        .find_map(|(id, ty)| {
+            let hir::Node::Block(blk) = self.tcx.hir().get(id?) else { return None };
+            self.could_remove_semicolon(blk, ty)
+        });
+        match remove_semicolon {
+            Some((sp, StatementAsExpression::NeedsBoxing)) => {
+                err.multipart_suggestion(
+                    "consider removing this semicolon and boxing the expressions",
+                    vec![
+                        (first_span.shrink_to_lo(), "Box::new(".to_string()),
+                        (first_span.shrink_to_hi(), ")".to_string()),
+                        (second_span.shrink_to_lo(), "Box::new(".to_string()),
+                        (second_span.shrink_to_hi(), ")".to_string()),
+                        (sp, String::new()),
+                    ],
+                    Applicability::MachineApplicable,
+                );
+            }
+            Some((sp, StatementAsExpression::CorrectType)) => {
+                err.span_suggestion_short(
+                    sp,
+                    "consider removing this semicolon",
+                    "",
+                    Applicability::MachineApplicable,
+                );
+            }
+            None => {
+                for (id, ty) in [(first_id, second_ty), (second_id, first_ty)] {
+                    if let Some(id) = id
+                        && let hir::Node::Block(blk) = self.tcx.hir().get(id)
+                        && self.consider_returning_binding(blk, ty, err)
+                    {
+                        break;
+                    }
+                }
+            }
+        }
+    }
+
+    pub(super) fn suggest_boxing_for_return_impl_trait(
+        &self,
+        err: &mut Diagnostic,
+        return_sp: Span,
+        arm_spans: impl Iterator<Item = Span>,
+    ) {
+        err.multipart_suggestion(
+            "you could change the return type to be a boxed trait object",
+            vec![
+                (return_sp.with_hi(return_sp.lo() + BytePos(4)), "Box<dyn".to_string()),
+                (return_sp.shrink_to_hi(), ">".to_string()),
+            ],
+            Applicability::MaybeIncorrect,
+        );
+        let sugg = arm_spans
+            .flat_map(|sp| {
+                [(sp.shrink_to_lo(), "Box::new(".to_string()), (sp.shrink_to_hi(), ")".to_string())]
+                    .into_iter()
+            })
+            .collect::<Vec<_>>();
+        err.multipart_suggestion(
+            "if you change the return type to expect trait objects, box the returned expressions",
+            sugg,
+            Applicability::MaybeIncorrect,
+        );
+    }
+
+    pub(super) fn suggest_tuple_pattern(
+        &self,
+        cause: &ObligationCause<'tcx>,
+        exp_found: &ty::error::ExpectedFound<Ty<'tcx>>,
+        diag: &mut Diagnostic,
+    ) {
+        // Heavily inspired by `FnCtxt::suggest_compatible_variants`, with
+        // some modifications due to that being in typeck and this being in infer.
+        if let ObligationCauseCode::Pattern { .. } = cause.code() {
+            if let ty::Adt(expected_adt, substs) = exp_found.expected.kind() {
+                let compatible_variants: Vec<_> = expected_adt
+                    .variants()
+                    .iter()
+                    .filter(|variant| {
+                        variant.fields.len() == 1 && variant.ctor_kind() == Some(CtorKind::Fn)
+                    })
+                    .filter_map(|variant| {
+                        let sole_field = &variant.fields[0];
+                        let sole_field_ty = sole_field.ty(self.tcx, substs);
+                        if self.same_type_modulo_infer(sole_field_ty, exp_found.found) {
+                            let variant_path =
+                                with_no_trimmed_paths!(self.tcx.def_path_str(variant.def_id));
+                            // FIXME #56861: DRYer prelude filtering
+                            if let Some(path) = variant_path.strip_prefix("std::prelude::") {
+                                if let Some((_, path)) = path.split_once("::") {
+                                    return Some(path.to_string());
+                                }
+                            }
+                            Some(variant_path)
+                        } else {
+                            None
+                        }
+                    })
+                    .collect();
+                match &compatible_variants[..] {
+                    [] => {}
+                    [variant] => {
+                        diag.multipart_suggestion_verbose(
+                            &format!("try wrapping the pattern in `{}`", variant),
+                            vec![
+                                (cause.span.shrink_to_lo(), format!("{}(", variant)),
+                                (cause.span.shrink_to_hi(), ")".to_string()),
+                            ],
+                            Applicability::MaybeIncorrect,
+                        );
+                    }
+                    _ => {
+                        // More than one matching variant.
+                        diag.multipart_suggestions(
+                            &format!(
+                                "try wrapping the pattern in a variant of `{}`",
+                                self.tcx.def_path_str(expected_adt.did())
+                            ),
+                            compatible_variants.into_iter().map(|variant| {
+                                vec![
+                                    (cause.span.shrink_to_lo(), format!("{}(", variant)),
+                                    (cause.span.shrink_to_hi(), ")".to_string()),
+                                ]
+                            }),
+                            Applicability::MaybeIncorrect,
+                        );
+                    }
+                }
+            }
+        }
+    }
+
+    /// A possible error is to forget to add `.await` when using futures:
+    ///
+    /// ```compile_fail,E0308
+    /// async fn make_u32() -> u32 {
+    ///     22
+    /// }
+    ///
+    /// fn take_u32(x: u32) {}
+    ///
+    /// async fn foo() {
+    ///     let x = make_u32();
+    ///     take_u32(x);
+    /// }
+    /// ```
+    ///
+    /// This routine checks if the found type `T` implements `Future<Output=U>` where `U` is the
+    /// expected type. If this is the case, and we are inside of an async body, it suggests adding
+    /// `.await` to the tail of the expression.
+    pub(super) fn suggest_await_on_expect_found(
+        &self,
+        cause: &ObligationCause<'tcx>,
+        exp_span: Span,
+        exp_found: &ty::error::ExpectedFound<Ty<'tcx>>,
+        diag: &mut Diagnostic,
+    ) {
+        debug!(
+            "suggest_await_on_expect_found: exp_span={:?}, expected_ty={:?}, found_ty={:?}",
+            exp_span, exp_found.expected, exp_found.found,
+        );
+
+        if let ObligationCauseCode::CompareImplItemObligation { .. } = cause.code() {
+            return;
+        }
+
+        match (
+            self.get_impl_future_output_ty(exp_found.expected),
+            self.get_impl_future_output_ty(exp_found.found),
+        ) {
+            (Some(exp), Some(found)) if self.same_type_modulo_infer(exp, found) => match cause
+                .code()
+            {
+                ObligationCauseCode::IfExpression(box IfExpressionCause { then_id, .. }) => {
+                    let then_span = self.find_block_span_from_hir_id(*then_id);
+                    diag.multipart_suggestion(
+                        "consider `await`ing on both `Future`s",
+                        vec![
+                            (then_span.shrink_to_hi(), ".await".to_string()),
+                            (exp_span.shrink_to_hi(), ".await".to_string()),
+                        ],
+                        Applicability::MaybeIncorrect,
+                    );
+                }
+                ObligationCauseCode::MatchExpressionArm(box MatchExpressionArmCause {
+                    prior_arms,
+                    ..
+                }) => {
+                    if let [.., arm_span] = &prior_arms[..] {
+                        diag.multipart_suggestion(
+                            "consider `await`ing on both `Future`s",
+                            vec![
+                                (arm_span.shrink_to_hi(), ".await".to_string()),
+                                (exp_span.shrink_to_hi(), ".await".to_string()),
+                            ],
+                            Applicability::MaybeIncorrect,
+                        );
+                    } else {
+                        diag.help("consider `await`ing on both `Future`s");
+                    }
+                }
+                _ => {
+                    diag.help("consider `await`ing on both `Future`s");
+                }
+            },
+            (_, Some(ty)) if self.same_type_modulo_infer(exp_found.expected, ty) => {
+                diag.span_suggestion_verbose(
+                    exp_span.shrink_to_hi(),
+                    "consider `await`ing on the `Future`",
+                    ".await",
+                    Applicability::MaybeIncorrect,
+                );
+            }
+            (Some(ty), _) if self.same_type_modulo_infer(ty, exp_found.found) => match cause.code()
+            {
+                ObligationCauseCode::Pattern { span: Some(then_span), .. } => {
+                    diag.span_suggestion_verbose(
+                        then_span.shrink_to_hi(),
+                        "consider `await`ing on the `Future`",
+                        ".await",
+                        Applicability::MaybeIncorrect,
+                    );
+                }
+                ObligationCauseCode::IfExpression(box IfExpressionCause { then_id, .. }) => {
+                    let then_span = self.find_block_span_from_hir_id(*then_id);
+                    diag.span_suggestion_verbose(
+                        then_span.shrink_to_hi(),
+                        "consider `await`ing on the `Future`",
+                        ".await",
+                        Applicability::MaybeIncorrect,
+                    );
+                }
+                ObligationCauseCode::MatchExpressionArm(box MatchExpressionArmCause {
+                    ref prior_arms,
+                    ..
+                }) => {
+                    diag.multipart_suggestion_verbose(
+                        "consider `await`ing on the `Future`",
+                        prior_arms
+                            .iter()
+                            .map(|arm| (arm.shrink_to_hi(), ".await".to_string()))
+                            .collect(),
+                        Applicability::MaybeIncorrect,
+                    );
+                }
+                _ => {}
+            },
+            _ => {}
+        }
+    }
+
+    pub(super) fn suggest_accessing_field_where_appropriate(
+        &self,
+        cause: &ObligationCause<'tcx>,
+        exp_found: &ty::error::ExpectedFound<Ty<'tcx>>,
+        diag: &mut Diagnostic,
+    ) {
+        debug!(
+            "suggest_accessing_field_where_appropriate(cause={:?}, exp_found={:?})",
+            cause, exp_found
+        );
+        if let ty::Adt(expected_def, expected_substs) = exp_found.expected.kind() {
+            if expected_def.is_enum() {
+                return;
+            }
+
+            if let Some((name, ty)) = expected_def
+                .non_enum_variant()
+                .fields
+                .iter()
+                .filter(|field| field.vis.is_accessible_from(field.did, self.tcx))
+                .map(|field| (field.name, field.ty(self.tcx, expected_substs)))
+                .find(|(_, ty)| self.same_type_modulo_infer(*ty, exp_found.found))
+            {
+                if let ObligationCauseCode::Pattern { span: Some(span), .. } = *cause.code() {
+                    if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) {
+                        let suggestion = if expected_def.is_struct() {
+                            format!("{}.{}", snippet, name)
+                        } else if expected_def.is_union() {
+                            format!("unsafe {{ {}.{} }}", snippet, name)
+                        } else {
+                            return;
+                        };
+                        diag.span_suggestion(
+                            span,
+                            &format!(
+                                "you might have meant to use field `{}` whose type is `{}`",
+                                name, ty
+                            ),
+                            suggestion,
+                            Applicability::MaybeIncorrect,
+                        );
+                    }
+                }
+            }
+        }
+    }
+
+    /// When encountering a case where `.as_ref()` on a `Result` or `Option` would be appropriate,
+    /// suggests it.
+    pub(super) fn suggest_as_ref_where_appropriate(
+        &self,
+        span: Span,
+        exp_found: &ty::error::ExpectedFound<Ty<'tcx>>,
+        diag: &mut Diagnostic,
+    ) {
+        if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span)
+            && let Some(msg) = self.should_suggest_as_ref(exp_found.expected, exp_found.found)
+        {
+            diag.span_suggestion(
+                span,
+                msg,
+                // HACK: fix issue# 100605, suggesting convert from &Option<T> to Option<&T>, remove the extra `&`
+                format!("{}.as_ref()", snippet.trim_start_matches('&')),
+                Applicability::MachineApplicable,
+            );
+        }
+    }
+
+    pub fn should_suggest_as_ref(&self, expected: Ty<'tcx>, found: Ty<'tcx>) -> Option<&str> {
+        if let (ty::Adt(exp_def, exp_substs), ty::Ref(_, found_ty, _)) =
+            (expected.kind(), found.kind())
+        {
+            if let ty::Adt(found_def, found_substs) = *found_ty.kind() {
+                if exp_def == &found_def {
+                    let have_as_ref = &[
+                        (
+                            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(|(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
+                            std::iter::zip(exp_substs.types(), found_substs.types())
+                        {
+                            match *exp_ty.kind() {
+                                ty::Ref(_, exp_ty, _) => {
+                                    match (exp_ty.kind(), found_ty.kind()) {
+                                        (_, ty::Param(_))
+                                        | (_, ty::Infer(_))
+                                        | (ty::Param(_), _)
+                                        | (ty::Infer(_), _) => {}
+                                        _ if self.same_type_modulo_infer(exp_ty, found_ty) => {}
+                                        _ => show_suggestion = false,
+                                    };
+                                }
+                                ty::Param(_) | ty::Infer(_) => {}
+                                _ => show_suggestion = false,
+                            }
+                        }
+                        if show_suggestion {
+                            return Some(*msg);
+                        }
+                    }
+                }
+            }
+        }
+        None
+    }
+
+    /// Try to find code with pattern `if Some(..) = expr`
+    /// use a `visitor` to mark the `if` which its span contains given error span,
+    /// and then try to find a assignment in the `cond` part, which span is equal with error span
+    pub(super) fn suggest_let_for_letchains(
+        &self,
+        err: &mut Diagnostic,
+        cause: &ObligationCause<'_>,
+        span: Span,
+    ) {
+        let hir = self.tcx.hir();
+        let fn_hir_id = hir.get_parent_node(cause.body_id);
+        if let Some(node) = self.tcx.hir().find(fn_hir_id) &&
+            let hir::Node::Item(hir::Item {
+                    kind: hir::ItemKind::Fn(_sig, _, body_id), ..
+                }) = node {
+        let body = hir.body(*body_id);
+
+        /// Find the if expression with given span
+        struct IfVisitor {
+            pub result: bool,
+            pub found_if: bool,
+            pub err_span: Span,
+        }
+
+        impl<'v> Visitor<'v> for IfVisitor {
+            fn visit_expr(&mut self, ex: &'v hir::Expr<'v>) {
+                if self.result { return; }
+                match ex.kind {
+                    hir::ExprKind::If(cond, _, _) => {
+                        self.found_if = true;
+                        walk_expr(self, cond);
+                        self.found_if = false;
+                    }
+                    _ => walk_expr(self, ex),
+                }
+            }
+
+            fn visit_stmt(&mut self, ex: &'v hir::Stmt<'v>) {
+                if let hir::StmtKind::Local(hir::Local {
+                        span, pat: hir::Pat{..}, ty: None, init: Some(_), ..
+                    }) = &ex.kind
+                    && self.found_if
+                    && span.eq(&self.err_span) {
+                        self.result = true;
+                }
+                walk_stmt(self, ex);
+            }
+
+            fn visit_body(&mut self, body: &'v hir::Body<'v>) {
+                hir::intravisit::walk_body(self, body);
+            }
+        }
+
+        let mut visitor = IfVisitor { err_span: span, found_if: false, result: false };
+        visitor.visit_body(&body);
+        if visitor.result {
+                err.subdiagnostic(SuggAddLetForLetChains{span: span.shrink_to_lo()});
+            }
+        }
+    }
+}
+
+impl<'tcx> TypeErrCtxt<'_, 'tcx> {
+    /// Be helpful when the user wrote `{... expr; }` and taking the `;` off
+    /// is enough to fix the error.
+    pub fn could_remove_semicolon(
+        &self,
+        blk: &'tcx hir::Block<'tcx>,
+        expected_ty: Ty<'tcx>,
+    ) -> Option<(Span, StatementAsExpression)> {
+        let blk = blk.innermost_block();
+        // Do not suggest if we have a tail expr.
+        if blk.expr.is_some() {
+            return None;
+        }
+        let last_stmt = blk.stmts.last()?;
+        let hir::StmtKind::Semi(ref last_expr) = last_stmt.kind else {
+            return None;
+        };
+        let last_expr_ty = self.typeck_results.as_ref()?.expr_ty_opt(*last_expr)?;
+        let needs_box = match (last_expr_ty.kind(), expected_ty.kind()) {
+            _ if last_expr_ty.references_error() => return None,
+            _ if self.same_type_modulo_infer(last_expr_ty, expected_ty) => {
+                StatementAsExpression::CorrectType
+            }
+            (ty::Opaque(last_def_id, _), ty::Opaque(exp_def_id, _))
+                if last_def_id == exp_def_id =>
+            {
+                StatementAsExpression::CorrectType
+            }
+            (ty::Opaque(last_def_id, last_bounds), ty::Opaque(exp_def_id, exp_bounds)) => {
+                debug!(
+                    "both opaque, likely future {:?} {:?} {:?} {:?}",
+                    last_def_id, last_bounds, exp_def_id, exp_bounds
+                );
+
+                let last_local_id = last_def_id.as_local()?;
+                let exp_local_id = exp_def_id.as_local()?;
+
+                match (
+                    &self.tcx.hir().expect_item(last_local_id).kind,
+                    &self.tcx.hir().expect_item(exp_local_id).kind,
+                ) {
+                    (
+                        hir::ItemKind::OpaqueTy(hir::OpaqueTy { bounds: last_bounds, .. }),
+                        hir::ItemKind::OpaqueTy(hir::OpaqueTy { bounds: exp_bounds, .. }),
+                    ) if std::iter::zip(*last_bounds, *exp_bounds).all(|(left, right)| {
+                        match (left, right) {
+                            (
+                                hir::GenericBound::Trait(tl, ml),
+                                hir::GenericBound::Trait(tr, mr),
+                            ) if tl.trait_ref.trait_def_id() == tr.trait_ref.trait_def_id()
+                                && ml == mr =>
+                            {
+                                true
+                            }
+                            (
+                                hir::GenericBound::LangItemTrait(langl, _, _, argsl),
+                                hir::GenericBound::LangItemTrait(langr, _, _, argsr),
+                            ) if langl == langr => {
+                                // FIXME: consider the bounds!
+                                debug!("{:?} {:?}", argsl, argsr);
+                                true
+                            }
+                            _ => false,
+                        }
+                    }) =>
+                    {
+                        StatementAsExpression::NeedsBoxing
+                    }
+                    _ => StatementAsExpression::CorrectType,
+                }
+            }
+            _ => return None,
+        };
+        let span = if last_stmt.span.from_expansion() {
+            let mac_call = rustc_span::source_map::original_sp(last_stmt.span, blk.span);
+            self.tcx.sess.source_map().mac_call_stmt_semi_span(mac_call)?
+        } else {
+            last_stmt.span.with_lo(last_stmt.span.hi() - BytePos(1))
+        };
+        Some((span, needs_box))
+    }
+
+    /// Suggest returning a local binding with a compatible type if the block
+    /// has no return expression.
+    pub fn consider_returning_binding(
+        &self,
+        blk: &'tcx hir::Block<'tcx>,
+        expected_ty: Ty<'tcx>,
+        err: &mut Diagnostic,
+    ) -> bool {
+        let blk = blk.innermost_block();
+        // Do not suggest if we have a tail expr.
+        if blk.expr.is_some() {
+            return false;
+        }
+        let mut shadowed = FxIndexSet::default();
+        let mut candidate_idents = vec![];
+        let mut find_compatible_candidates = |pat: &hir::Pat<'_>| {
+            if let hir::PatKind::Binding(_, hir_id, ident, _) = &pat.kind
+                && let Some(pat_ty) = self
+                    .typeck_results
+                    .as_ref()
+                    .and_then(|typeck_results| typeck_results.node_type_opt(*hir_id))
+            {
+                let pat_ty = self.resolve_vars_if_possible(pat_ty);
+                if self.same_type_modulo_infer(pat_ty, expected_ty)
+                    && !(pat_ty, expected_ty).references_error()
+                    && shadowed.insert(ident.name)
+                {
+                    candidate_idents.push((*ident, pat_ty));
+                }
+            }
+            true
+        };
+
+        let hir = self.tcx.hir();
+        for stmt in blk.stmts.iter().rev() {
+            let hir::StmtKind::Local(local) = &stmt.kind else { continue; };
+            local.pat.walk(&mut find_compatible_candidates);
+        }
+        match hir.find(hir.get_parent_node(blk.hir_id)) {
+            Some(hir::Node::Expr(hir::Expr { hir_id, .. })) => {
+                match hir.find(hir.get_parent_node(*hir_id)) {
+                    Some(hir::Node::Arm(hir::Arm { pat, .. })) => {
+                        pat.walk(&mut find_compatible_candidates);
+                    }
+                    Some(
+                        hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(_, _, body), .. })
+                        | hir::Node::ImplItem(hir::ImplItem {
+                            kind: hir::ImplItemKind::Fn(_, body),
+                            ..
+                        })
+                        | hir::Node::TraitItem(hir::TraitItem {
+                            kind: hir::TraitItemKind::Fn(_, hir::TraitFn::Provided(body)),
+                            ..
+                        })
+                        | hir::Node::Expr(hir::Expr {
+                            kind: hir::ExprKind::Closure(hir::Closure { body, .. }),
+                            ..
+                        }),
+                    ) => {
+                        for param in hir.body(*body).params {
+                            param.pat.walk(&mut find_compatible_candidates);
+                        }
+                    }
+                    Some(hir::Node::Expr(hir::Expr {
+                        kind:
+                            hir::ExprKind::If(
+                                hir::Expr { kind: hir::ExprKind::Let(let_), .. },
+                                then_block,
+                                _,
+                            ),
+                        ..
+                    })) if then_block.hir_id == *hir_id => {
+                        let_.pat.walk(&mut find_compatible_candidates);
+                    }
+                    _ => {}
+                }
+            }
+            _ => {}
+        }
+
+        match &candidate_idents[..] {
+            [(ident, _ty)] => {
+                let sm = self.tcx.sess.source_map();
+                if let Some(stmt) = blk.stmts.last() {
+                    let stmt_span = sm.stmt_span(stmt.span, blk.span);
+                    let sugg = if sm.is_multiline(blk.span)
+                        && let Some(spacing) = sm.indentation_before(stmt_span)
+                    {
+                        format!("\n{spacing}{ident}")
+                    } else {
+                        format!(" {ident}")
+                    };
+                    err.span_suggestion_verbose(
+                        stmt_span.shrink_to_hi(),
+                        format!("consider returning the local binding `{ident}`"),
+                        sugg,
+                        Applicability::MaybeIncorrect,
+                    );
+                } else {
+                    let sugg = if sm.is_multiline(blk.span)
+                        && let Some(spacing) = sm.indentation_before(blk.span.shrink_to_lo())
+                    {
+                        format!("\n{spacing}    {ident}\n{spacing}")
+                    } else {
+                        format!(" {ident} ")
+                    };
+                    let left_span = sm.span_through_char(blk.span, '{').shrink_to_hi();
+                    err.span_suggestion_verbose(
+                        sm.span_extend_while(left_span, |c| c.is_whitespace()).unwrap_or(left_span),
+                        format!("consider returning the local binding `{ident}`"),
+                        sugg,
+                        Applicability::MaybeIncorrect,
+                    );
+                }
+                true
+            }
+            values if (1..3).contains(&values.len()) => {
+                let spans = values.iter().map(|(ident, _)| ident.span).collect::<Vec<_>>();
+                err.span_note(spans, "consider returning one of these bindings");
+                true
+            }
+            _ => false,
+        }
+    }
+}
index 2bcb47cc38399f85b07436e792a707f3ab68bf1f..2ce7cd8beba98a5e8cf4f154161e0e325df5f484 100644 (file)
@@ -80,7 +80,6 @@ pub struct InferOk<'tcx, T> {
 }
 pub type InferResult<'tcx, T> = Result<InferOk<'tcx, T>, TypeError<'tcx>>;
 
-pub type Bound<T> = Option<T>;
 pub type UnitResult<'tcx> = RelateResult<'tcx, ()>; // "unify result"
 pub type FixupResult<'tcx, T> = Result<T, FixupError<'tcx>>; // "fixup result"
 
@@ -334,9 +333,6 @@ pub struct InferCtxt<'tcx> {
     /// bound.
     universe: Cell<ty::UniverseIndex>,
 
-    normalize_fn_sig_for_diagnostic:
-        Option<Lrc<dyn Fn(&InferCtxt<'tcx>, ty::PolyFnSig<'tcx>) -> ty::PolyFnSig<'tcx>>>,
-
     /// During coherence we have to assume that other crates may add
     /// additional impls which we currently don't know about.
     ///
@@ -573,8 +569,6 @@ pub struct InferCtxtBuilder<'tcx> {
     considering_regions: bool,
     /// Whether we are in coherence mode.
     intercrate: bool,
-    normalize_fn_sig_for_diagnostic:
-        Option<Lrc<dyn Fn(&InferCtxt<'tcx>, ty::PolyFnSig<'tcx>) -> ty::PolyFnSig<'tcx>>>,
 }
 
 pub trait TyCtxtInferExt<'tcx> {
@@ -587,7 +581,6 @@ fn infer_ctxt(self) -> InferCtxtBuilder<'tcx> {
             tcx: self,
             defining_use_anchor: DefiningAnchor::Error,
             considering_regions: true,
-            normalize_fn_sig_for_diagnostic: None,
             intercrate: false,
         }
     }
@@ -615,14 +608,6 @@ 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
@@ -644,13 +629,7 @@ pub fn build_with_canonical<T>(
     }
 
     pub fn build(&mut self) -> InferCtxt<'tcx> {
-        let InferCtxtBuilder {
-            tcx,
-            defining_use_anchor,
-            considering_regions,
-            ref normalize_fn_sig_for_diagnostic,
-            intercrate,
-        } = *self;
+        let InferCtxtBuilder { tcx, defining_use_anchor, considering_regions, intercrate } = *self;
         InferCtxt {
             tcx,
             defining_use_anchor,
@@ -666,9 +645,6 @@ pub fn build(&mut self) -> InferCtxt<'tcx> {
             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()),
             intercrate,
         }
     }
@@ -709,7 +685,12 @@ impl<'tcx> InferCtxt<'tcx> {
     /// Creates a `TypeErrCtxt` for emitting various inference errors.
     /// During typeck, use `FnCtxt::err_ctxt` instead.
     pub fn err_ctxt(&self) -> TypeErrCtxt<'_, 'tcx> {
-        TypeErrCtxt { infcx: self, typeck_results: None, fallback_has_occurred: false }
+        TypeErrCtxt {
+            infcx: self,
+            typeck_results: None,
+            fallback_has_occurred: false,
+            normalize_fn_sig: Box::new(|fn_sig| fn_sig),
+        }
     }
 
     pub fn is_in_snapshot(&self) -> bool {
diff --git a/compiler/rustc_infer/src/infer/note.rs b/compiler/rustc_infer/src/infer/note.rs
new file mode 100644 (file)
index 0000000..2ccbd16
--- /dev/null
@@ -0,0 +1,203 @@
+impl<'tcx> TypeErrCtxt<'_, 'tcx> {
+    fn note_error_origin(
+        &self,
+        err: &mut Diagnostic,
+        cause: &ObligationCause<'tcx>,
+        exp_found: Option<ty::error::ExpectedFound<Ty<'tcx>>>,
+        terr: TypeError<'tcx>,
+    ) {
+        match *cause.code() {
+            ObligationCauseCode::Pattern { origin_expr: true, span: Some(span), root_ty } => {
+                let ty = self.resolve_vars_if_possible(root_ty);
+                if !matches!(ty.kind(), ty::Infer(ty::InferTy::TyVar(_) | ty::InferTy::FreshTy(_)))
+                {
+                    // don't show type `_`
+                    if span.desugaring_kind() == Some(DesugaringKind::ForLoop)
+                        && let ty::Adt(def, substs) = ty.kind()
+                        && Some(def.did()) == self.tcx.get_diagnostic_item(sym::Option)
+                    {
+                        err.span_label(span, format!("this is an iterator with items of type `{}`", substs.type_at(0)));
+                    } else {
+                    err.span_label(span, format!("this expression has type `{}`", ty));
+                }
+                }
+                if let Some(ty::error::ExpectedFound { found, .. }) = exp_found
+                    && ty.is_box() && ty.boxed_ty() == found
+                    && let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span)
+                {
+                    err.span_suggestion(
+                        span,
+                        "consider dereferencing the boxed value",
+                        format!("*{}", snippet),
+                        Applicability::MachineApplicable,
+                    );
+                }
+            }
+            ObligationCauseCode::Pattern { origin_expr: false, span: Some(span), .. } => {
+                err.span_label(span, "expected due to this");
+            }
+            ObligationCauseCode::MatchExpressionArm(box MatchExpressionArmCause {
+                arm_block_id,
+                arm_span,
+                arm_ty,
+                prior_arm_block_id,
+                prior_arm_span,
+                prior_arm_ty,
+                source,
+                ref prior_arms,
+                scrut_hir_id,
+                opt_suggest_box_span,
+                scrut_span,
+                ..
+            }) => match source {
+                hir::MatchSource::TryDesugar => {
+                    if let Some(ty::error::ExpectedFound { expected, .. }) = exp_found {
+                        let scrut_expr = self.tcx.hir().expect_expr(scrut_hir_id);
+                        let scrut_ty = if let hir::ExprKind::Call(_, args) = &scrut_expr.kind {
+                            let arg_expr = args.first().expect("try desugaring call w/out arg");
+                            self.typeck_results.as_ref().and_then(|typeck_results| {
+                                typeck_results.expr_ty_opt(arg_expr)
+                            })
+                        } else {
+                            bug!("try desugaring w/out call expr as scrutinee");
+                        };
+
+                        match scrut_ty {
+                            Some(ty) if expected == ty => {
+                                let source_map = self.tcx.sess.source_map();
+                                err.span_suggestion(
+                                    source_map.end_point(cause.span),
+                                    "try removing this `?`",
+                                    "",
+                                    Applicability::MachineApplicable,
+                                );
+                            }
+                            _ => {}
+                        }
+                    }
+                }
+                _ => {
+                    // `prior_arm_ty` can be `!`, `expected` will have better info when present.
+                    let t = self.resolve_vars_if_possible(match exp_found {
+                        Some(ty::error::ExpectedFound { expected, .. }) => expected,
+                        _ => prior_arm_ty,
+                    });
+                    let source_map = self.tcx.sess.source_map();
+                    let mut any_multiline_arm = source_map.is_multiline(arm_span);
+                    if prior_arms.len() <= 4 {
+                        for sp in prior_arms {
+                            any_multiline_arm |= source_map.is_multiline(*sp);
+                            err.span_label(*sp, format!("this is found to be of type `{}`", t));
+                        }
+                    } else if let Some(sp) = prior_arms.last() {
+                        any_multiline_arm |= source_map.is_multiline(*sp);
+                        err.span_label(
+                            *sp,
+                            format!("this and all prior arms are found to be of type `{}`", t),
+                        );
+                    }
+                    let outer_error_span = if any_multiline_arm {
+                        // Cover just `match` and the scrutinee expression, not
+                        // the entire match body, to reduce diagram noise.
+                        cause.span.shrink_to_lo().to(scrut_span)
+                    } else {
+                        cause.span
+                    };
+                    let msg = "`match` arms have incompatible types";
+                    err.span_label(outer_error_span, msg);
+                    self.suggest_remove_semi_or_return_binding(
+                        err,
+                        prior_arm_block_id,
+                        prior_arm_ty,
+                        prior_arm_span,
+                        arm_block_id,
+                        arm_ty,
+                        arm_span,
+                    );
+                    if let Some(ret_sp) = opt_suggest_box_span {
+                        // Get return type span and point to it.
+                        self.suggest_boxing_for_return_impl_trait(
+                            err,
+                            ret_sp,
+                            prior_arms.iter().chain(std::iter::once(&arm_span)).map(|s| *s),
+                        );
+                    }
+                }
+            },
+            ObligationCauseCode::IfExpression(box IfExpressionCause {
+                then_id,
+                else_id,
+                then_ty,
+                else_ty,
+                outer_span,
+                opt_suggest_box_span,
+            }) => {
+                let then_span = self.find_block_span_from_hir_id(then_id);
+                let else_span = self.find_block_span_from_hir_id(else_id);
+                err.span_label(then_span, "expected because of this");
+                if let Some(sp) = outer_span {
+                    err.span_label(sp, "`if` and `else` have incompatible types");
+                }
+                self.suggest_remove_semi_or_return_binding(
+                    err,
+                    Some(then_id),
+                    then_ty,
+                    then_span,
+                    Some(else_id),
+                    else_ty,
+                    else_span,
+                );
+                if let Some(ret_sp) = opt_suggest_box_span {
+                    self.suggest_boxing_for_return_impl_trait(
+                        err,
+                        ret_sp,
+                        [then_span, else_span].into_iter(),
+                    );
+                }
+            }
+            ObligationCauseCode::LetElse => {
+                err.help("try adding a diverging expression, such as `return` or `panic!(..)`");
+                err.help("...or use `match` instead of `let...else`");
+            }
+            _ => {
+                if let ObligationCauseCode::BindingObligation(_, span)
+                | ObligationCauseCode::ExprBindingObligation(_, span, ..)
+                = cause.code().peel_derives()
+                    && let TypeError::RegionsPlaceholderMismatch = terr
+                {
+                    err.span_note( * span,
+                    "the lifetime requirement is introduced here");
+                }
+            }
+        }
+    }
+}
+
+impl<'tcx> InferCtxt<'tcx> {
+    /// Given a [`hir::Block`], get the span of its last expression or
+    /// statement, peeling off any inner blocks.
+    pub fn find_block_span(&self, block: &'tcx hir::Block<'tcx>) -> Span {
+        let block = block.innermost_block();
+        if let Some(expr) = &block.expr {
+            expr.span
+        } else if let Some(stmt) = block.stmts.last() {
+            // possibly incorrect trailing `;` in the else arm
+            stmt.span
+        } else {
+            // empty block; point at its entirety
+            block.span
+        }
+    }
+
+    /// Given a [`hir::HirId`] for a block, get the span of its last expression
+    /// or statement, peeling off any inner blocks.
+    pub fn find_block_span_from_hir_id(&self, hir_id: hir::HirId) -> Span {
+        match self.tcx.hir().get(hir_id) {
+            hir::Node::Block(blk) => self.find_block_span(blk),
+            // The parser was in a weird state if either of these happen, but
+            // it's better not to panic.
+            hir::Node::Expr(e) => e.span,
+            _ => rustc_span::DUMMY_SP,
+        }
+    }
+}
index 7f1d21bf1d8b0cdebacd4fb2dc8b1ab73776d69d..89d9450cf4e89a0b6335647b5bf5f2446f7207bd 100644 (file)
@@ -12,6 +12,7 @@
 use rustc_borrowck as mir_borrowck;
 use rustc_codegen_ssa::traits::CodegenBackend;
 use rustc_data_structures::parallel;
+use rustc_data_structures::steal::Steal;
 use rustc_data_structures::sync::{Lrc, OnceCell, WorkerLocal};
 use rustc_errors::{ErrorGuaranteed, PResult};
 use rustc_expand::base::{ExtCtxt, LintStoreExpand, ResolverExpand};
@@ -157,7 +158,7 @@ pub fn create_resolver(
     sess: Lrc<Session>,
     metadata_loader: Box<MetadataLoaderDyn>,
     krate: &ast::Crate,
-    crate_name: &str,
+    crate_name: Symbol,
 ) -> BoxedResolver {
     trace!("create_resolver");
     BoxedResolver::new(sess, move |sess, resolver_arenas| {
@@ -170,7 +171,7 @@ pub fn register_plugins<'a>(
     metadata_loader: &'a dyn MetadataLoader,
     register_lints: impl Fn(&Session, &mut LintStore),
     mut krate: ast::Crate,
-    crate_name: &str,
+    crate_name: Symbol,
 ) -> Result<(ast::Crate, LintStore)> {
     krate = sess.time("attributes_injection", || {
         rustc_builtin_macros::cmdline_attrs::inject(
@@ -207,10 +208,7 @@ pub fn register_plugins<'a>(
         });
     }
 
-    let mut lint_store = rustc_lint::new_lint_store(
-        sess.opts.unstable_opts.no_interleave_lints,
-        sess.enable_internal_lints(),
-    );
+    let mut lint_store = rustc_lint::new_lint_store(sess.enable_internal_lints());
     register_lints(sess, &mut lint_store);
 
     let registrars =
@@ -230,19 +228,21 @@ fn pre_expansion_lint<'a>(
     lint_store: &LintStore,
     registered_tools: &RegisteredTools,
     check_node: impl EarlyCheckNode<'a>,
-    node_name: &str,
+    node_name: Symbol,
 ) {
-    sess.prof.generic_activity_with_arg("pre_AST_expansion_lint_checks", node_name).run(|| {
-        rustc_lint::check_ast_node(
-            sess,
-            true,
-            lint_store,
-            registered_tools,
-            None,
-            rustc_lint::BuiltinCombinedPreExpansionLintPass::new(),
-            check_node,
-        );
-    });
+    sess.prof.generic_activity_with_arg("pre_AST_expansion_lint_checks", node_name.as_str()).run(
+        || {
+            rustc_lint::check_ast_node(
+                sess,
+                true,
+                lint_store,
+                registered_tools,
+                None,
+                rustc_lint::BuiltinCombinedPreExpansionLintPass::new(),
+                check_node,
+            );
+        },
+    );
 }
 
 // Cannot implement directly for `LintStore` due to trait coherence.
@@ -256,7 +256,7 @@ fn pre_expansion_lint(
         node_id: ast::NodeId,
         attrs: &[ast::Attribute],
         items: &[rustc_ast::ptr::P<ast::Item>],
-        name: &str,
+        name: Symbol,
     ) {
         pre_expansion_lint(sess, self.0, registered_tools, (node_id, attrs, items), name);
     }
@@ -270,7 +270,7 @@ pub fn configure_and_expand(
     sess: &Session,
     lint_store: &LintStore,
     mut krate: ast::Crate,
-    crate_name: &str,
+    crate_name: Symbol,
     resolver: &mut Resolver<'_>,
 ) -> Result<ast::Crate> {
     trace!("configure_and_expand");
@@ -464,7 +464,7 @@ fn generated_output_paths(
     sess: &Session,
     outputs: &OutputFilenames,
     exact_name: bool,
-    crate_name: &str,
+    crate_name: Symbol,
 ) -> Vec<PathBuf> {
     let mut out_filenames = Vec::new();
     for output_type in sess.opts.output_types.keys() {
@@ -663,7 +663,7 @@ pub fn prepare_outputs(
     compiler: &Compiler,
     krate: &ast::Crate,
     boxed_resolver: &RefCell<BoxedResolver>,
-    crate_name: &str,
+    crate_name: Symbol,
 ) -> Result<OutputFilenames> {
     let _timer = sess.timer("prepare_outputs");
 
@@ -773,7 +773,7 @@ pub fn create_global_ctxt<'tcx>(
     dep_graph: DepGraph,
     resolver: Rc<RefCell<BoxedResolver>>,
     outputs: OutputFilenames,
-    crate_name: &str,
+    crate_name: Symbol,
     queries: &'tcx OnceCell<TcxQueries<'tcx>>,
     global_ctxt: &'tcx OnceCell<GlobalCtxt<'tcx>>,
     arena: &'tcx WorkerLocal<Arena<'tcx>>,
@@ -804,6 +804,12 @@ pub fn create_global_ctxt<'tcx>(
         TcxQueries::new(local_providers, extern_providers, query_result_on_disk_cache)
     });
 
+    let ty::ResolverOutputs {
+        global_ctxt: untracked_resolutions,
+        ast_lowering: untracked_resolver_for_lowering,
+        untracked,
+    } = resolver_outputs;
+
     let gcx = sess.time("setup_global_ctxt", || {
         global_ctxt.get_or_init(move || {
             TyCtxt::create_global_ctxt(
@@ -811,7 +817,8 @@ pub fn create_global_ctxt<'tcx>(
                 lint_store,
                 arena,
                 hir_arena,
-                resolver_outputs,
+                untracked_resolutions,
+                untracked,
                 krate,
                 dep_graph,
                 queries.on_disk_cache.as_ref().map(OnDiskCache::as_dyn),
@@ -823,7 +830,12 @@ pub fn create_global_ctxt<'tcx>(
         })
     });
 
-    QueryContext { gcx }
+    let mut qcx = QueryContext { gcx };
+    qcx.enter(|tcx| {
+        tcx.feed_unit_query()
+            .resolver_for_lowering(tcx.arena.alloc(Steal::new(untracked_resolver_for_lowering)))
+    });
+    qcx
 }
 
 /// Runs the resolution, type-checking, region checking and other
@@ -968,12 +980,10 @@ fn analysis(tcx: TyCtxt<'_>, (): ()) -> Result<()> {
 pub fn start_codegen<'tcx>(
     codegen_backend: &dyn CodegenBackend,
     tcx: TyCtxt<'tcx>,
-    outputs: &OutputFilenames,
 ) -> Box<dyn Any> {
     info!("Pre-codegen\n{:?}", tcx.debug_stats());
 
-    let (metadata, need_metadata_module) =
-        rustc_metadata::fs::encode_and_write_metadata(tcx, outputs);
+    let (metadata, need_metadata_module) = rustc_metadata::fs::encode_and_write_metadata(tcx);
 
     let codegen = tcx.sess.time("codegen_crate", move || {
         codegen_backend.codegen_crate(tcx, metadata, need_metadata_module)
@@ -989,7 +999,7 @@ pub fn start_codegen<'tcx>(
     info!("Post-codegen\n{:?}", tcx.debug_stats());
 
     if tcx.sess.opts.output_types.contains_key(&OutputType::Mir) {
-        if let Err(error) = rustc_mir_transform::dump_mir::emit_mir(tcx, outputs) {
+        if let Err(error) = rustc_mir_transform::dump_mir::emit_mir(tcx) {
             tcx.sess.emit_err(CantEmitMIR { error });
             tcx.sess.abort_if_errors();
         }
index fc0b11183f7bf250105b2f65ae9a131f4e26b876..39e1f2204b002010176277dadfb531098f096730 100644 (file)
 use rustc_session::config::{self, OutputFilenames, OutputType};
 use rustc_session::{output::find_crate_name, Session};
 use rustc_span::symbol::sym;
+use rustc_span::Symbol;
 use std::any::Any;
 use std::cell::{Ref, RefCell, RefMut};
 use std::rc::Rc;
+use std::sync::Arc;
 
 /// Represent the result of a query.
 ///
@@ -73,7 +75,7 @@ pub struct Queries<'tcx> {
 
     dep_graph_future: Query<Option<DepGraphFuture>>,
     parse: Query<ast::Crate>,
-    crate_name: Query<String>,
+    crate_name: Query<Symbol>,
     register_plugins: Query<(ast::Crate, Lrc<LintStore>)>,
     expansion: Query<(Lrc<ast::Crate>, Rc<RefCell<BoxedResolver>>, Lrc<LintStore>)>,
     dep_graph: Query<DepGraph>,
@@ -134,7 +136,7 @@ pub fn register_plugins(&self) -> Result<&Query<(ast::Crate, Lrc<LintStore>)>> {
                 &*self.codegen_backend().metadata_loader(),
                 self.compiler.register_lints.as_deref().unwrap_or_else(|| empty),
                 krate,
-                &crate_name,
+                crate_name,
             )?;
 
             // Compute the dependency graph (in the background). We want to do
@@ -148,7 +150,7 @@ pub fn register_plugins(&self) -> Result<&Query<(ast::Crate, Lrc<LintStore>)>> {
         })
     }
 
-    pub fn crate_name(&self) -> Result<&Query<String>> {
+    pub fn crate_name(&self) -> Result<&Query<Symbol>> {
         self.crate_name.compute(|| {
             Ok({
                 let parse_result = self.parse()?;
@@ -164,7 +166,7 @@ pub fn expansion(
     ) -> Result<&Query<(Lrc<ast::Crate>, Rc<RefCell<BoxedResolver>>, Lrc<LintStore>)>> {
         trace!("expansion");
         self.expansion.compute(|| {
-            let crate_name = self.crate_name()?.peek().clone();
+            let crate_name = *self.crate_name()?.peek();
             let (krate, lint_store) = self.register_plugins()?.take();
             let _timer = self.session().timer("configure_and_expand");
             let sess = self.session();
@@ -172,10 +174,10 @@ pub fn expansion(
                 sess.clone(),
                 self.codegen_backend().metadata_loader(),
                 &krate,
-                &crate_name,
+                crate_name,
             );
             let krate = resolver.access(|resolver| {
-                passes::configure_and_expand(sess, &lint_store, krate, &crate_name, resolver)
+                passes::configure_and_expand(sess, &lint_store, krate, crate_name, resolver)
             })?;
             Ok((Lrc::new(krate), Rc::new(RefCell::new(resolver)), lint_store))
         })
@@ -200,21 +202,21 @@ fn dep_graph(&self) -> Result<&Query<DepGraph>> {
     pub fn prepare_outputs(&self) -> Result<&Query<OutputFilenames>> {
         self.prepare_outputs.compute(|| {
             let (krate, boxed_resolver, _) = &*self.expansion()?.peek();
-            let crate_name = self.crate_name()?.peek();
+            let crate_name = *self.crate_name()?.peek();
             passes::prepare_outputs(
                 self.session(),
                 self.compiler,
                 krate,
                 &*boxed_resolver,
-                &crate_name,
+                crate_name,
             )
         })
     }
 
     pub fn global_ctxt(&'tcx self) -> Result<&Query<QueryContext<'tcx>>> {
         self.global_ctxt.compute(|| {
-            let crate_name = self.crate_name()?.peek().clone();
-            let outputs = self.prepare_outputs()?.peek().clone();
+            let crate_name = *self.crate_name()?.peek();
+            let outputs = self.prepare_outputs()?.take();
             let dep_graph = self.dep_graph()?.peek().clone();
             let (krate, resolver, lint_store) = self.expansion()?.take();
             Ok(passes::create_global_ctxt(
@@ -224,7 +226,7 @@ pub fn global_ctxt(&'tcx self) -> Result<&Query<QueryContext<'tcx>>> {
                 dep_graph,
                 resolver,
                 outputs,
-                &crate_name,
+                crate_name,
                 &self.queries,
                 &self.gcx,
                 &self.arena,
@@ -235,7 +237,6 @@ pub fn global_ctxt(&'tcx self) -> Result<&Query<QueryContext<'tcx>>> {
 
     pub fn ongoing_codegen(&'tcx self) -> Result<&Query<Box<dyn Any>>> {
         self.ongoing_codegen.compute(|| {
-            let outputs = self.prepare_outputs()?;
             self.global_ctxt()?.peek_mut().enter(|tcx| {
                 tcx.analysis(()).ok();
 
@@ -249,7 +250,7 @@ pub fn ongoing_codegen(&'tcx self) -> Result<&Query<Box<dyn Any>>> {
                 // Hook for UI tests.
                 Self::check_for_rustc_errors_attr(tcx);
 
-                Ok(passes::start_codegen(&***self.codegen_backend(), tcx, &*outputs.peek()))
+                Ok(passes::start_codegen(&***self.codegen_backend(), tcx))
             })
         })
     }
@@ -293,8 +294,10 @@ pub fn linker(&'tcx self) -> Result<Linker> {
         let codegen_backend = self.codegen_backend().clone();
 
         let dep_graph = self.dep_graph()?.peek().clone();
-        let prepare_outputs = self.prepare_outputs()?.take();
-        let crate_hash = self.global_ctxt()?.peek_mut().enter(|tcx| tcx.crate_hash(LOCAL_CRATE));
+        let (crate_hash, prepare_outputs) = self
+            .global_ctxt()?
+            .peek_mut()
+            .enter(|tcx| (tcx.crate_hash(LOCAL_CRATE), tcx.output_filenames(()).clone()));
         let ongoing_codegen = self.ongoing_codegen()?.take();
 
         Ok(Linker {
@@ -316,7 +319,7 @@ pub struct Linker {
 
     // compilation outputs
     dep_graph: DepGraph,
-    prepare_outputs: OutputFilenames,
+    prepare_outputs: Arc<OutputFilenames>,
     crate_hash: Svh,
     ongoing_codegen: Box<dyn Any>,
 }
index a03e7b0dae527344a17f8edfd6d958cceed0853a..e903cb86dd20438a9264fcdf67bfedf6f3783cb4 100644 (file)
@@ -25,7 +25,6 @@
 use rustc_target::spec::{RelroLevel, SanitizerSet, SplitDebuginfo, StackProtector, TlsModel};
 
 use std::collections::{BTreeMap, BTreeSet};
-use std::iter::FromIterator;
 use std::num::NonZeroUsize;
 use std::path::{Path, PathBuf};
 
@@ -666,7 +665,6 @@ macro_rules! untracked {
     untracked!(mir_pretty_relative_line_numbers, true);
     untracked!(nll_facts, true);
     untracked!(no_analysis, true);
-    untracked!(no_interleave_lints, true);
     untracked!(no_leak_check, true);
     untracked!(no_parallel_llvm, true);
     untracked!(parse_only, true);
@@ -748,6 +746,7 @@ macro_rules! tracked {
     tracked!(link_only, true);
     tracked!(llvm_plugins, vec![String::from("plugin_name")]);
     tracked!(location_detail, LocationDetail { file: true, line: false, column: false });
+    tracked!(maximal_hir_to_mir_coverage, true);
     tracked!(merge_functions, Some(MergeFunctions::Disabled));
     tracked!(mir_emit_retag, true);
     tracked!(mir_enable_passes, vec![("DestProp".to_string(), false)]);
index ad685c2ad19f43a29e85959c2702d1d60bf0b954..23294dc2e1b6a952412fc16e55cbb61eef627059 100644 (file)
@@ -19,4 +19,4 @@ unicode-xid = "0.2.0"
 unic-emoji-char = "0.9.0"
 
 [dev-dependencies]
-expect-test = "1.0"
+expect-test = "1.4.0"
index 3fbabbc6344a7f3518b10e11b1869bb78d9fd948..50d6d5b9bab91a0bc08807c708ad7f02858d2842 100644 (file)
@@ -34,7 +34,6 @@
 use self::LiteralKind::*;
 use self::TokenKind::*;
 use crate::cursor::EOF_CHAR;
-use std::convert::TryFrom;
 
 /// Parsed token.
 /// It doesn't contain information about data that has been parsed,
index 825093384fba7f4688948e4f1eb963decf7fc9e3..0932eee92373d764361d9a87249d6693c9c353cd 100644 (file)
@@ -53,7 +53,8 @@
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
 use rustc_span::{BytePos, InnerSpan, Span};
 use rustc_target::abi::{Abi, VariantIdx};
-use rustc_trait_selection::traits::{self, misc::can_type_implement_copy};
+use rustc_trait_selection::infer::{InferCtxtExt, TyCtxtInferExt};
+use rustc_trait_selection::traits::{self, misc::can_type_implement_copy, EvaluationResult};
 
 use crate::nonstandard_style::{method_context, MethodLateContext};
 
@@ -96,6 +97,7 @@ fn pierce_parens(mut expr: &ast::Expr) -> &ast::Expr {
 }
 
 impl EarlyLintPass for WhileTrue {
+    #[inline]
     fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &ast::Expr) {
         if let ast::ExprKind::While(cond, _, label) = &e.kind
             && let cond = pierce_parens(cond)
@@ -259,7 +261,7 @@ fn check_pat(&mut self, cx: &LateContext<'_>, pat: &hir::Pat<'_>) {
                 }
                 if let PatKind::Binding(binding_annot, _, ident, None) = fieldpat.pat.kind {
                     if cx.tcx.find_field_index(ident, &variant)
-                        == Some(cx.tcx.field_index(fieldpat.hir_id, cx.typeck_results()))
+                        == Some(cx.typeck_results().field_index(fieldpat.hir_id))
                     {
                         cx.struct_span_lint(
                             NON_SHORTHAND_FIELD_PATTERNS,
@@ -360,6 +362,7 @@ fn check_attribute(&mut self, cx: &EarlyContext<'_>, attr: &ast::Attribute) {
         }
     }
 
+    #[inline]
     fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &ast::Expr) {
         if let ast::ExprKind::Block(ref blk, _) = e.kind {
             // Don't warn about generated blocks; that'll just pollute the output.
@@ -582,6 +585,7 @@ fn check_missing_docs_attrs(
 }
 
 impl<'tcx> LateLintPass<'tcx> for MissingDoc {
+    #[inline]
     fn enter_lint_attrs(&mut self, _cx: &LateContext<'_>, attrs: &[ast::Attribute]) {
         let doc_hidden = self.doc_hidden()
             || attrs.iter().any(|attr| {
@@ -750,10 +754,39 @@ fn check_item(&mut self, cx: &LateContext<'_>, item: &hir::Item<'_>) {
         if def.has_dtor(cx.tcx) {
             return;
         }
+
+        // If the type contains a raw pointer, it may represent something like a handle,
+        // and recommending Copy might be a bad idea.
+        for field in def.all_fields() {
+            let did = field.did;
+            if cx.tcx.type_of(did).is_unsafe_ptr() {
+                return;
+            }
+        }
         let param_env = ty::ParamEnv::empty();
         if ty.is_copy_modulo_regions(cx.tcx, param_env) {
             return;
         }
+
+        // We shouldn't recommend implementing `Copy` on stateful things,
+        // such as iterators.
+        if let Some(iter_trait) = cx.tcx.get_diagnostic_item(sym::Iterator) {
+            if cx.tcx.infer_ctxt().build().type_implements_trait(iter_trait, [ty], param_env)
+                == EvaluationResult::EvaluatedToOk
+            {
+                return;
+            }
+        }
+
+        // Default value of clippy::trivially_copy_pass_by_ref
+        const MAX_SIZE: u64 = 256;
+
+        if let Some(size) = cx.layout_of(ty).ok().map(|l| l.size.bytes()) {
+            if size > MAX_SIZE {
+                return;
+            }
+        }
+
         if can_type_implement_copy(
             cx.tcx,
             param_env,
index a7a4d0ca52772a7b15c754b22aef35cfb9512dad..5f84d5c8b949575394d401a287bbe1b025563376 100644 (file)
 use rustc_span::symbol::Ident;
 use rustc_span::Span;
 
-use std::slice;
-
-macro_rules! run_early_pass { ($cx:expr, $f:ident, $($args:expr),*) => ({
+macro_rules! lint_callback { ($cx:expr, $f:ident, $($args:expr),*) => ({
     $cx.pass.$f(&$cx.context, $($args),*);
 }) }
 
+/// Implements the AST traversal for early lint passes. `T` provides the the
+/// `check_*` methods.
 pub struct EarlyContextAndPass<'a, T: EarlyLintPass> {
     context: EarlyContext<'a>,
     pass: T,
 }
 
 impl<'a, T: EarlyLintPass> EarlyContextAndPass<'a, T> {
-    fn check_id(&mut self, id: ast::NodeId) {
+    // This always-inlined function is for the hot call site.
+    #[inline(always)]
+    fn inlined_check_id(&mut self, id: ast::NodeId) {
         for early_lint in self.context.buffered.take(id) {
             let BufferedEarlyLint { span, msg, node_id: _, lint_id, diagnostic } = early_lint;
             self.context.lookup_with_diagnostics(
@@ -50,6 +52,11 @@ fn check_id(&mut self, id: ast::NodeId) {
         }
     }
 
+    // This non-inlined function is for the cold call sites.
+    fn check_id(&mut self, id: ast::NodeId) {
+        self.inlined_check_id(id)
+    }
+
     /// Merge the lints specified by any lint attributes into the
     /// current lint context, call the provided function, then reset the
     /// lints in effect to their previous state.
@@ -61,12 +68,12 @@ fn with_lint_attrs<F>(&mut self, id: ast::NodeId, attrs: &'a [ast::Attribute], f
         debug!(?id);
         let push = self.context.builder.push(attrs, is_crate_node, None);
 
-        self.check_id(id);
+        self.inlined_check_id(id);
         debug!("early context: enter_attrs({:?})", attrs);
-        run_early_pass!(self, enter_lint_attrs, attrs);
+        lint_callback!(self, enter_lint_attrs, attrs);
         f(self);
         debug!("early context: exit_attrs({:?})", attrs);
-        run_early_pass!(self, exit_lint_attrs, attrs);
+        lint_callback!(self, exit_lint_attrs, attrs);
         self.context.builder.pop(push);
     }
 }
@@ -74,16 +81,16 @@ fn with_lint_attrs<F>(&mut self, id: ast::NodeId, attrs: &'a [ast::Attribute], f
 impl<'a, T: EarlyLintPass> ast_visit::Visitor<'a> for EarlyContextAndPass<'a, T> {
     fn visit_param(&mut self, param: &'a ast::Param) {
         self.with_lint_attrs(param.id, &param.attrs, |cx| {
-            run_early_pass!(cx, check_param, param);
+            lint_callback!(cx, check_param, param);
             ast_visit::walk_param(cx, param);
         });
     }
 
     fn visit_item(&mut self, it: &'a ast::Item) {
         self.with_lint_attrs(it.id, &it.attrs, |cx| {
-            run_early_pass!(cx, check_item, it);
+            lint_callback!(cx, check_item, it);
             ast_visit::walk_item(cx, it);
-            run_early_pass!(cx, check_item_post, it);
+            lint_callback!(cx, check_item_post, it);
         })
     }
 
@@ -94,10 +101,10 @@ fn visit_foreign_item(&mut self, it: &'a ast::ForeignItem) {
     }
 
     fn visit_pat(&mut self, p: &'a ast::Pat) {
-        run_early_pass!(self, check_pat, p);
+        lint_callback!(self, check_pat, p);
         self.check_id(p.id);
         ast_visit::walk_pat(self, p);
-        run_early_pass!(self, check_pat_post, p);
+        lint_callback!(self, check_pat_post, p);
     }
 
     fn visit_pat_field(&mut self, field: &'a ast::PatField) {
@@ -113,7 +120,7 @@ fn visit_anon_const(&mut self, c: &'a ast::AnonConst) {
 
     fn visit_expr(&mut self, e: &'a ast::Expr) {
         self.with_lint_attrs(e.id, &e.attrs, |cx| {
-            run_early_pass!(cx, check_expr, e);
+            lint_callback!(cx, check_expr, e);
             ast_visit::walk_expr(cx, e);
         })
     }
@@ -134,7 +141,7 @@ fn visit_stmt(&mut self, s: &'a ast::Stmt) {
         // Note that statements get their attributes from
         // the AST struct that they wrap (e.g. an item)
         self.with_lint_attrs(s.id, s.attrs(), |cx| {
-            run_early_pass!(cx, check_stmt, s);
+            lint_callback!(cx, check_stmt, s);
             cx.check_id(s.id);
         });
         // The visitor for the AST struct wrapped
@@ -145,7 +152,7 @@ fn visit_stmt(&mut self, s: &'a ast::Stmt) {
     }
 
     fn visit_fn(&mut self, fk: ast_visit::FnKind<'a>, span: Span, id: ast::NodeId) {
-        run_early_pass!(self, check_fn, fk, span, id);
+        lint_callback!(self, check_fn, fk, span, id);
         self.check_id(id);
         ast_visit::walk_fn(self, fk);
 
@@ -173,37 +180,37 @@ fn visit_field_def(&mut self, s: &'a ast::FieldDef) {
 
     fn visit_variant(&mut self, v: &'a ast::Variant) {
         self.with_lint_attrs(v.id, &v.attrs, |cx| {
-            run_early_pass!(cx, check_variant, v);
+            lint_callback!(cx, check_variant, v);
             ast_visit::walk_variant(cx, v);
         })
     }
 
     fn visit_ty(&mut self, t: &'a ast::Ty) {
-        run_early_pass!(self, check_ty, t);
+        lint_callback!(self, check_ty, t);
         self.check_id(t.id);
         ast_visit::walk_ty(self, t);
     }
 
     fn visit_ident(&mut self, ident: Ident) {
-        run_early_pass!(self, check_ident, ident);
+        lint_callback!(self, check_ident, ident);
     }
 
     fn visit_local(&mut self, l: &'a ast::Local) {
         self.with_lint_attrs(l.id, &l.attrs, |cx| {
-            run_early_pass!(cx, check_local, l);
+            lint_callback!(cx, check_local, l);
             ast_visit::walk_local(cx, l);
         })
     }
 
     fn visit_block(&mut self, b: &'a ast::Block) {
-        run_early_pass!(self, check_block, b);
+        lint_callback!(self, check_block, b);
         self.check_id(b.id);
         ast_visit::walk_block(self, b);
     }
 
     fn visit_arm(&mut self, a: &'a ast::Arm) {
         self.with_lint_attrs(a.id, &a.attrs, |cx| {
-            run_early_pass!(cx, check_arm, a);
+            lint_callback!(cx, check_arm, a);
             ast_visit::walk_arm(cx, a);
         })
     }
@@ -222,19 +229,19 @@ fn visit_expr_post(&mut self, e: &'a ast::Expr) {
     }
 
     fn visit_generic_arg(&mut self, arg: &'a ast::GenericArg) {
-        run_early_pass!(self, check_generic_arg, arg);
+        lint_callback!(self, check_generic_arg, arg);
         ast_visit::walk_generic_arg(self, arg);
     }
 
     fn visit_generic_param(&mut self, param: &'a ast::GenericParam) {
         self.with_lint_attrs(param.id, &param.attrs, |cx| {
-            run_early_pass!(cx, check_generic_param, param);
+            lint_callback!(cx, check_generic_param, param);
             ast_visit::walk_generic_param(cx, param);
         });
     }
 
     fn visit_generics(&mut self, g: &'a ast::Generics) {
-        run_early_pass!(self, check_generics, g);
+        lint_callback!(self, check_generics, g);
         ast_visit::walk_generics(self, g);
     }
 
@@ -243,18 +250,18 @@ fn visit_where_predicate(&mut self, p: &'a ast::WherePredicate) {
     }
 
     fn visit_poly_trait_ref(&mut self, t: &'a ast::PolyTraitRef) {
-        run_early_pass!(self, check_poly_trait_ref, t);
+        lint_callback!(self, check_poly_trait_ref, t);
         ast_visit::walk_poly_trait_ref(self, t);
     }
 
     fn visit_assoc_item(&mut self, item: &'a ast::AssocItem, ctxt: ast_visit::AssocCtxt) {
         self.with_lint_attrs(item.id, &item.attrs, |cx| match ctxt {
             ast_visit::AssocCtxt::Trait => {
-                run_early_pass!(cx, check_trait_item, item);
+                lint_callback!(cx, check_trait_item, item);
                 ast_visit::walk_assoc_item(cx, item, ctxt);
             }
             ast_visit::AssocCtxt::Impl => {
-                run_early_pass!(cx, check_impl_item, item);
+                lint_callback!(cx, check_impl_item, item);
                 ast_visit::walk_assoc_item(cx, item, ctxt);
             }
         });
@@ -275,50 +282,48 @@ fn visit_path_segment(&mut self, s: &'a ast::PathSegment) {
     }
 
     fn visit_attribute(&mut self, attr: &'a ast::Attribute) {
-        run_early_pass!(self, check_attribute, attr);
+        lint_callback!(self, check_attribute, attr);
     }
 
     fn visit_mac_def(&mut self, mac: &'a ast::MacroDef, id: ast::NodeId) {
-        run_early_pass!(self, check_mac_def, mac);
+        lint_callback!(self, check_mac_def, mac);
         self.check_id(id);
     }
 
     fn visit_mac_call(&mut self, mac: &'a ast::MacCall) {
-        run_early_pass!(self, check_mac, mac);
+        lint_callback!(self, check_mac, mac);
         ast_visit::walk_mac(self, mac);
     }
 }
 
-struct EarlyLintPassObjects<'a> {
-    lints: &'a mut [EarlyLintPassObject],
+// Combines multiple lint passes into a single pass, at runtime. Each
+// `check_foo` method in `$methods` within this pass simply calls `check_foo`
+// once per `$pass`. Compare with `declare_combined_early_lint_pass`, which is
+// similar, but combines lint passes at compile time.
+struct RuntimeCombinedEarlyLintPass<'a> {
+    passes: &'a mut [EarlyLintPassObject],
 }
 
 #[allow(rustc::lint_pass_impl_without_macro)]
-impl LintPass for EarlyLintPassObjects<'_> {
+impl LintPass for RuntimeCombinedEarlyLintPass<'_> {
     fn name(&self) -> &'static str {
         panic!()
     }
 }
 
-macro_rules! expand_early_lint_pass_impl_methods {
-    ([$($(#[$attr:meta])* fn $name:ident($($param:ident: $arg:ty),*);)*]) => (
-        $(fn $name(&mut self, context: &EarlyContext<'_>, $($param: $arg),*) {
-            for obj in self.lints.iter_mut() {
-                obj.$name(context, $($param),*);
-            }
-        })*
-    )
-}
-
-macro_rules! early_lint_pass_impl {
-    ([], [$($methods:tt)*]) => (
-        impl EarlyLintPass for EarlyLintPassObjects<'_> {
-            expand_early_lint_pass_impl_methods!([$($methods)*]);
+macro_rules! impl_early_lint_pass {
+    ([], [$($(#[$attr:meta])* fn $f:ident($($param:ident: $arg:ty),*);)*]) => (
+        impl EarlyLintPass for RuntimeCombinedEarlyLintPass<'_> {
+            $(fn $f(&mut self, context: &EarlyContext<'_>, $($param: $arg),*) {
+                for pass in self.passes.iter_mut() {
+                    pass.$f(context, $($param),*);
+                }
+            })*
         }
     )
 }
 
-crate::early_lint_methods!(early_lint_pass_impl, []);
+crate::early_lint_methods!(impl_early_lint_pass, []);
 
 /// Early lints work on different nodes - either on the crate root, or on freshly loaded modules.
 /// This trait generalizes over those nodes.
@@ -327,7 +332,7 @@ pub trait EarlyCheckNode<'a>: Copy {
     fn attrs<'b>(self) -> &'b [ast::Attribute]
     where
         'a: 'b;
-    fn check<'b>(self, cx: &mut EarlyContextAndPass<'b, impl EarlyLintPass>)
+    fn check<'b, T: EarlyLintPass>(self, cx: &mut EarlyContextAndPass<'b, T>)
     where
         'a: 'b;
 }
@@ -342,13 +347,13 @@ fn attrs<'b>(self) -> &'b [ast::Attribute]
     {
         &self.attrs
     }
-    fn check<'b>(self, cx: &mut EarlyContextAndPass<'b, impl EarlyLintPass>)
+    fn check<'b, T: EarlyLintPass>(self, cx: &mut EarlyContextAndPass<'b, T>)
     where
         'a: 'b,
     {
-        run_early_pass!(cx, check_crate, self);
+        lint_callback!(cx, check_crate, self);
         ast_visit::walk_crate(cx, self);
-        run_early_pass!(cx, check_crate_post, self);
+        lint_callback!(cx, check_crate_post, self);
     }
 }
 
@@ -362,7 +367,7 @@ fn attrs<'b>(self) -> &'b [ast::Attribute]
     {
         self.1
     }
-    fn check<'b>(self, cx: &mut EarlyContextAndPass<'b, impl EarlyLintPass>)
+    fn check<'b, T: EarlyLintPass>(self, cx: &mut EarlyContextAndPass<'b, T>)
     where
         'a: 'b,
     {
@@ -371,87 +376,52 @@ fn check<'b>(self, cx: &mut EarlyContextAndPass<'b, impl EarlyLintPass>)
     }
 }
 
-fn early_lint_node<'a>(
-    sess: &Session,
-    warn_about_weird_lints: bool,
-    lint_store: &LintStore,
-    registered_tools: &RegisteredTools,
-    buffered: LintBuffer,
-    pass: impl EarlyLintPass,
-    check_node: impl EarlyCheckNode<'a>,
-) -> LintBuffer {
-    let mut cx = EarlyContextAndPass {
-        context: EarlyContext::new(
-            sess,
-            warn_about_weird_lints,
-            lint_store,
-            registered_tools,
-            buffered,
-        ),
-        pass,
-    };
-
-    cx.with_lint_attrs(check_node.id(), check_node.attrs(), |cx| check_node.check(cx));
-    cx.context.buffered
-}
-
 pub fn check_ast_node<'a>(
     sess: &Session,
     pre_expansion: bool,
     lint_store: &LintStore,
     registered_tools: &RegisteredTools,
     lint_buffer: Option<LintBuffer>,
-    builtin_lints: impl EarlyLintPass,
+    builtin_lints: impl EarlyLintPass + 'static,
     check_node: impl EarlyCheckNode<'a>,
 ) {
+    let context = EarlyContext::new(
+        sess,
+        !pre_expansion,
+        lint_store,
+        registered_tools,
+        lint_buffer.unwrap_or_default(),
+    );
+
+    // Note: `passes` is often empty. In that case, it's faster to run
+    // `builtin_lints` directly rather than bundling it up into the
+    // `RuntimeCombinedEarlyLintPass`.
     let passes =
         if pre_expansion { &lint_store.pre_expansion_passes } else { &lint_store.early_passes };
-    let mut passes: Vec<_> = passes.iter().map(|p| (p)()).collect();
-    let mut buffered = lint_buffer.unwrap_or_default();
-
-    if sess.opts.unstable_opts.no_interleave_lints {
-        for (i, pass) in passes.iter_mut().enumerate() {
-            buffered =
-                sess.prof.verbose_generic_activity_with_arg("run_lint", pass.name()).run(|| {
-                    early_lint_node(
-                        sess,
-                        !pre_expansion && i == 0,
-                        lint_store,
-                        registered_tools,
-                        buffered,
-                        EarlyLintPassObjects { lints: slice::from_mut(pass) },
-                        check_node,
-                    )
-                });
-        }
+    if passes.is_empty() {
+        check_ast_node_inner(sess, check_node, context, builtin_lints);
     } else {
-        buffered = early_lint_node(
-            sess,
-            !pre_expansion,
-            lint_store,
-            registered_tools,
-            buffered,
-            builtin_lints,
-            check_node,
-        );
-
-        if !passes.is_empty() {
-            buffered = early_lint_node(
-                sess,
-                false,
-                lint_store,
-                registered_tools,
-                buffered,
-                EarlyLintPassObjects { lints: &mut passes[..] },
-                check_node,
-            );
-        }
+        let mut passes: Vec<_> = passes.iter().map(|mk_pass| (mk_pass)()).collect();
+        passes.push(Box::new(builtin_lints));
+        let pass = RuntimeCombinedEarlyLintPass { passes: &mut passes[..] };
+        check_ast_node_inner(sess, check_node, context, pass);
     }
+}
+
+pub fn check_ast_node_inner<'a, T: EarlyLintPass>(
+    sess: &Session,
+    check_node: impl EarlyCheckNode<'a>,
+    context: EarlyContext<'_>,
+    pass: T,
+) {
+    let mut cx = EarlyContextAndPass { context, pass };
+
+    cx.with_lint_attrs(check_node.id(), check_node.attrs(), |cx| check_node.check(cx));
 
     // All of the buffered lints should have been emitted at this point.
     // If not, that means that we somehow buffered a lint for a node id
     // that was not lint-checked (perhaps it doesn't exist?). This is a bug.
-    for (id, lints) in buffered.map {
+    for (id, lints) in cx.context.buffered.map {
         for early_lint in lints {
             sess.delay_span_bug(
                 early_lint.span,
index 7106e75dba290ebcac26a9deac25964eff0afaec..dc2f5c0e2967e86e45c838e288272132b5eb4bf4 100644 (file)
@@ -121,6 +121,7 @@ fn check_attribute(&mut self, cx: &EarlyContext<'_>, attr: &ast::Attribute) {
         }
     }
 
+    #[inline]
     fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &ast::Expr) {
         // byte strings are already handled well enough by `EscapeError::NonAsciiCharInByteString`
         match &expr.kind {
index a6c7e819482c25c992f4f125a4d6f6ae530875f7..4f92661dbd3342198d286c717b67a26bd7039bf6 100644 (file)
@@ -117,7 +117,7 @@ impl<'tcx> LateLintPass<'tcx> for TyTyKind {
     fn check_path(
         &mut self,
         cx: &LateContext<'tcx>,
-        path: &'tcx rustc_hir::Path<'tcx>,
+        path: &rustc_hir::Path<'tcx>,
         _: rustc_hir::HirId,
     ) {
         if let Some(segment) = path.segments.iter().nth_back(1)
index f484e31ba15088489840cd6c982a96d1784d33d1..e2876938d70566477329cc94541c81478a3894f1 100644 (file)
@@ -28,7 +28,6 @@
 
 use std::any::Any;
 use std::cell::Cell;
-use std::slice;
 
 /// Extract the `LintStore` from the query context.
 /// This function exists because we've erased `LintStore` as `dyn Any` in the context.
@@ -41,7 +40,9 @@ macro_rules! lint_callback { ($cx:expr, $f:ident, $($args:expr),*) => ({
     $cx.pass.$f(&$cx.context, $($args),*);
 }) }
 
-struct LateContextAndPass<'tcx, T: LateLintPass<'tcx>> {
+/// Implements the AST traversal for late lint passes. `T` provides the the
+/// `check_*` methods.
+pub struct LateContextAndPass<'tcx, T: LateLintPass<'tcx>> {
     context: LateContext<'tcx>,
     pass: T,
 }
@@ -292,7 +293,7 @@ fn visit_lifetime(&mut self, lt: &'tcx hir::Lifetime) {
         hir_visit::walk_lifetime(self, lt);
     }
 
-    fn visit_path(&mut self, p: &'tcx hir::Path<'tcx>, id: hir::HirId) {
+    fn visit_path(&mut self, p: &hir::Path<'tcx>, id: hir::HirId) {
         lint_callback!(self, check_path, p, id);
         hir_visit::walk_path(self, p);
     }
@@ -302,56 +303,72 @@ fn visit_attribute(&mut self, attr: &'tcx ast::Attribute) {
     }
 }
 
-struct LateLintPassObjects<'a, 'tcx> {
-    lints: &'a mut [LateLintPassObject<'tcx>],
+// Combines multiple lint passes into a single pass, at runtime. Each
+// `check_foo` method in `$methods` within this pass simply calls `check_foo`
+// once per `$pass`. Compare with `declare_combined_late_lint_pass`, which is
+// similar, but combines lint passes at compile time.
+struct RuntimeCombinedLateLintPass<'a, 'tcx> {
+    passes: &'a mut [LateLintPassObject<'tcx>],
 }
 
 #[allow(rustc::lint_pass_impl_without_macro)]
-impl LintPass for LateLintPassObjects<'_, '_> {
+impl LintPass for RuntimeCombinedLateLintPass<'_, '_> {
     fn name(&self) -> &'static str {
         panic!()
     }
 }
 
-macro_rules! expand_late_lint_pass_impl_methods {
-    ([$hir:tt], [$($(#[$attr:meta])* fn $name:ident($($param:ident: $arg:ty),*);)*]) => (
-        $(fn $name(&mut self, context: &LateContext<$hir>, $($param: $arg),*) {
-            for obj in self.lints.iter_mut() {
-                obj.$name(context, $($param),*);
-            }
-        })*
-    )
-}
-
-macro_rules! late_lint_pass_impl {
-    ([], [$hir:tt], $methods:tt) => {
-        impl<$hir> LateLintPass<$hir> for LateLintPassObjects<'_, $hir> {
-            expand_late_lint_pass_impl_methods!([$hir], $methods);
+macro_rules! impl_late_lint_pass {
+    ([], [$($(#[$attr:meta])* fn $f:ident($($param:ident: $arg:ty),*);)*]) => {
+        impl<'tcx> LateLintPass<'tcx> for RuntimeCombinedLateLintPass<'_, 'tcx> {
+            $(fn $f(&mut self, context: &LateContext<'tcx>, $($param: $arg),*) {
+                for pass in self.passes.iter_mut() {
+                    pass.$f(context, $($param),*);
+                }
+            })*
         }
     };
 }
 
-crate::late_lint_methods!(late_lint_pass_impl, [], ['tcx]);
+crate::late_lint_methods!(impl_late_lint_pass, []);
 
-fn late_lint_mod_pass<'tcx, T: LateLintPass<'tcx>>(
+pub(super) fn late_lint_mod<'tcx, T: LateLintPass<'tcx> + 'tcx>(
     tcx: TyCtxt<'tcx>,
     module_def_id: LocalDefId,
-    pass: T,
+    builtin_lints: T,
 ) {
-    let effective_visibilities = &tcx.effective_visibilities(());
-
     let context = LateContext {
         tcx,
         enclosing_body: None,
         cached_typeck_results: Cell::new(None),
         param_env: ty::ParamEnv::empty(),
-        effective_visibilities,
+        effective_visibilities: &tcx.effective_visibilities(()),
         lint_store: unerased_lint_store(tcx),
         last_node_with_lint_attrs: tcx.hir().local_def_id_to_hir_id(module_def_id),
         generics: None,
         only_module: true,
     };
 
+    // Note: `passes` is often empty. In that case, it's faster to run
+    // `builtin_lints` directly rather than bundling it up into the
+    // `RuntimeCombinedLateLintPass`.
+    let mut passes: Vec<_> =
+        unerased_lint_store(tcx).late_module_passes.iter().map(|mk_pass| (mk_pass)(tcx)).collect();
+    if passes.is_empty() {
+        late_lint_mod_inner(tcx, module_def_id, context, builtin_lints);
+    } else {
+        passes.push(Box::new(builtin_lints));
+        let pass = RuntimeCombinedLateLintPass { passes: &mut passes[..] };
+        late_lint_mod_inner(tcx, module_def_id, context, pass);
+    }
+}
+
+fn late_lint_mod_inner<'tcx, T: LateLintPass<'tcx>>(
+    tcx: TyCtxt<'tcx>,
+    module_def_id: LocalDefId,
+    context: LateContext<'tcx>,
+    pass: T,
+) {
     let mut cx = LateContextAndPass { context, pass };
 
     let (module, _span, hir_id) = tcx.hir().get_module(module_def_id);
@@ -365,46 +382,43 @@ fn late_lint_mod_pass<'tcx, T: LateLintPass<'tcx>>(
     }
 }
 
-pub fn late_lint_mod<'tcx, T: LateLintPass<'tcx>>(
-    tcx: TyCtxt<'tcx>,
-    module_def_id: LocalDefId,
-    builtin_lints: T,
-) {
-    if tcx.sess.opts.unstable_opts.no_interleave_lints {
-        // These passes runs in late_lint_crate with -Z no_interleave_lints
-        return;
-    }
-
-    late_lint_mod_pass(tcx, module_def_id, builtin_lints);
-
-    let mut passes: Vec<_> =
-        unerased_lint_store(tcx).late_module_passes.iter().map(|pass| (pass)(tcx)).collect();
-
-    if !passes.is_empty() {
-        late_lint_mod_pass(tcx, module_def_id, LateLintPassObjects { lints: &mut passes[..] });
-    }
-}
-
-fn late_lint_pass_crate<'tcx, T: LateLintPass<'tcx>>(tcx: TyCtxt<'tcx>, pass: T) {
-    let effective_visibilities = &tcx.effective_visibilities(());
-
+fn late_lint_crate<'tcx, T: LateLintPass<'tcx> + 'tcx>(tcx: TyCtxt<'tcx>, builtin_lints: T) {
     let context = LateContext {
         tcx,
         enclosing_body: None,
         cached_typeck_results: Cell::new(None),
         param_env: ty::ParamEnv::empty(),
-        effective_visibilities,
+        effective_visibilities: &tcx.effective_visibilities(()),
         lint_store: unerased_lint_store(tcx),
         last_node_with_lint_attrs: hir::CRATE_HIR_ID,
         generics: None,
         only_module: false,
     };
 
+    // Note: `passes` is often empty. In that case, it's faster to run
+    // `builtin_lints` directly rather than bundling it up into the
+    // `RuntimeCombinedLateLintPass`.
+    let mut passes: Vec<_> =
+        unerased_lint_store(tcx).late_passes.iter().map(|mk_pass| (mk_pass)(tcx)).collect();
+    if passes.is_empty() {
+        late_lint_crate_inner(tcx, context, builtin_lints);
+    } else {
+        passes.push(Box::new(builtin_lints));
+        let pass = RuntimeCombinedLateLintPass { passes: &mut passes[..] };
+        late_lint_crate_inner(tcx, context, pass);
+    }
+}
+
+fn late_lint_crate_inner<'tcx, T: LateLintPass<'tcx>>(
+    tcx: TyCtxt<'tcx>,
+    context: LateContext<'tcx>,
+    pass: T,
+) {
     let mut cx = LateContextAndPass { context, pass };
 
     // Visit the whole crate.
     cx.with_lint_attrs(hir::CRATE_HIR_ID, |cx| {
-        // since the root module isn't visited as an item (because it isn't an
+        // Since the root module isn't visited as an item (because it isn't an
         // item), warn for it here.
         lint_callback!(cx, check_crate,);
         tcx.hir().walk_toplevel_module(cx);
@@ -413,41 +427,8 @@ fn late_lint_pass_crate<'tcx, T: LateLintPass<'tcx>>(tcx: TyCtxt<'tcx>, pass: T)
     })
 }
 
-fn late_lint_crate<'tcx, T: LateLintPass<'tcx>>(tcx: TyCtxt<'tcx>, builtin_lints: T) {
-    let mut passes =
-        unerased_lint_store(tcx).late_passes.iter().map(|p| (p)(tcx)).collect::<Vec<_>>();
-
-    if !tcx.sess.opts.unstable_opts.no_interleave_lints {
-        if !passes.is_empty() {
-            late_lint_pass_crate(tcx, LateLintPassObjects { lints: &mut passes[..] });
-        }
-
-        late_lint_pass_crate(tcx, builtin_lints);
-    } else {
-        for pass in &mut passes {
-            tcx.sess.prof.verbose_generic_activity_with_arg("run_late_lint", pass.name()).run(
-                || {
-                    late_lint_pass_crate(tcx, LateLintPassObjects { lints: slice::from_mut(pass) });
-                },
-            );
-        }
-
-        let mut passes: Vec<_> =
-            unerased_lint_store(tcx).late_module_passes.iter().map(|pass| (pass)(tcx)).collect();
-
-        for pass in &mut passes {
-            tcx.sess
-                .prof
-                .verbose_generic_activity_with_arg("run_late_module_lint", pass.name())
-                .run(|| {
-                    late_lint_pass_crate(tcx, LateLintPassObjects { lints: slice::from_mut(pass) });
-                });
-        }
-    }
-}
-
 /// Performs lint checking on a crate.
-pub fn check_crate<'tcx, T: LateLintPass<'tcx>>(
+pub fn check_crate<'tcx, T: LateLintPass<'tcx> + 'tcx>(
     tcx: TyCtxt<'tcx>,
     builtin_lints: impl FnOnce() -> T + Send,
 ) {
index b6027476adfd97f3d2f8c05062fc1d652d44d890..11022eb80ea5ff04bd713ee1ba29c27af2d5cc55 100644 (file)
@@ -127,132 +127,115 @@ fn lint_mod(tcx: TyCtxt<'_>, module_def_id: LocalDefId) {
     late::late_lint_mod(tcx, module_def_id, BuiltinCombinedModuleLateLintPass::new());
 }
 
-macro_rules! pre_expansion_lint_passes {
-    ($macro:path, $args:tt) => {
-        $macro!($args, [KeywordIdents: KeywordIdents,]);
-    };
-}
-
-macro_rules! early_lint_passes {
-    ($macro:path, $args:tt) => {
-        $macro!(
-            $args,
-            [
-                UnusedParens: UnusedParens,
-                UnusedBraces: UnusedBraces,
-                UnusedImportBraces: UnusedImportBraces,
-                UnsafeCode: UnsafeCode,
-                SpecialModuleName: SpecialModuleName,
-                AnonymousParameters: AnonymousParameters,
-                EllipsisInclusiveRangePatterns: EllipsisInclusiveRangePatterns::default(),
-                NonCamelCaseTypes: NonCamelCaseTypes,
-                DeprecatedAttr: DeprecatedAttr::new(),
-                WhileTrue: WhileTrue,
-                NonAsciiIdents: NonAsciiIdents,
-                HiddenUnicodeCodepoints: HiddenUnicodeCodepoints,
-                IncompleteFeatures: IncompleteFeatures,
-                RedundantSemicolons: RedundantSemicolons,
-                UnusedDocComment: UnusedDocComment,
-                UnexpectedCfgs: UnexpectedCfgs,
-            ]
-        );
-    };
-}
-
-macro_rules! declare_combined_early_pass {
-    ([$name:ident], $passes:tt) => (
-        early_lint_methods!(declare_combined_early_lint_pass, [pub $name, $passes]);
-    )
-}
-
-pre_expansion_lint_passes!(declare_combined_early_pass, [BuiltinCombinedPreExpansionLintPass]);
-early_lint_passes!(declare_combined_early_pass, [BuiltinCombinedEarlyLintPass]);
-
-macro_rules! late_lint_passes {
-    ($macro:path, $args:tt) => {
-        $macro!(
-            $args,
-            [
-                // Tracks state across modules
-                UnnameableTestItems: UnnameableTestItems::new(),
-                // Tracks attributes of parents
-                MissingDoc: MissingDoc::new(),
-                // Builds a global list of all impls of `Debug`.
-                // FIXME: Turn the computation of types which implement Debug into a query
-                // and change this to a module lint pass
-                MissingDebugImplementations: MissingDebugImplementations::default(),
-                // Keeps a global list of foreign declarations.
-                ClashingExternDeclarations: ClashingExternDeclarations::new(),
-            ]
-        );
-    };
-}
-
-macro_rules! late_lint_mod_passes {
-    ($macro:path, $args:tt) => {
-        $macro!(
-            $args,
-            [
-                ForLoopsOverFallibles: ForLoopsOverFallibles,
-                DerefIntoDynSupertrait: DerefIntoDynSupertrait,
-                HardwiredLints: HardwiredLints,
-                ImproperCTypesDeclarations: ImproperCTypesDeclarations,
-                ImproperCTypesDefinitions: ImproperCTypesDefinitions,
-                VariantSizeDifferences: VariantSizeDifferences,
-                BoxPointers: BoxPointers,
-                PathStatements: PathStatements,
-                LetUnderscore: LetUnderscore,
-                // Depends on referenced function signatures in expressions
-                UnusedResults: UnusedResults,
-                NonUpperCaseGlobals: NonUpperCaseGlobals,
-                NonShorthandFieldPatterns: NonShorthandFieldPatterns,
-                UnusedAllocation: UnusedAllocation,
-                // Depends on types used in type definitions
-                MissingCopyImplementations: MissingCopyImplementations,
-                // Depends on referenced function signatures in expressions
-                MutableTransmutes: MutableTransmutes,
-                TypeAliasBounds: TypeAliasBounds,
-                TrivialConstraints: TrivialConstraints,
-                TypeLimits: TypeLimits::new(),
-                NonSnakeCase: NonSnakeCase,
-                InvalidNoMangleItems: InvalidNoMangleItems,
-                // Depends on effective visibilities
-                UnreachablePub: UnreachablePub,
-                ExplicitOutlivesRequirements: ExplicitOutlivesRequirements,
-                InvalidValue: InvalidValue,
-                DerefNullPtr: DerefNullPtr,
-                // May Depend on constants elsewhere
-                UnusedBrokenConst: UnusedBrokenConst,
-                UnstableFeatures: UnstableFeatures,
-                ArrayIntoIter: ArrayIntoIter::default(),
-                DropTraitConstraints: DropTraitConstraints,
-                TemporaryCStringAsPtr: TemporaryCStringAsPtr,
-                NonPanicFmt: NonPanicFmt,
-                NoopMethodCall: NoopMethodCall,
-                EnumIntrinsicsNonEnums: EnumIntrinsicsNonEnums,
-                InvalidAtomicOrdering: InvalidAtomicOrdering,
-                NamedAsmLabels: NamedAsmLabels,
-                OpaqueHiddenInferredBound: OpaqueHiddenInferredBound,
-            ]
-        );
-    };
-}
-
-macro_rules! declare_combined_late_pass {
-    ([$v:vis $name:ident], $passes:tt) => (
-        late_lint_methods!(declare_combined_late_lint_pass, [$v $name, $passes], ['tcx]);
-    )
-}
-
-// FIXME: Make a separate lint type which do not require typeck tables
-late_lint_passes!(declare_combined_late_pass, [pub BuiltinCombinedLateLintPass]);
-
-late_lint_mod_passes!(declare_combined_late_pass, [BuiltinCombinedModuleLateLintPass]);
-
-pub fn new_lint_store(no_interleave_lints: bool, internal_lints: bool) -> LintStore {
+early_lint_methods!(
+    declare_combined_early_lint_pass,
+    [
+        pub BuiltinCombinedPreExpansionLintPass,
+        [
+            KeywordIdents: KeywordIdents,
+        ]
+    ]
+);
+
+early_lint_methods!(
+    declare_combined_early_lint_pass,
+    [
+        pub BuiltinCombinedEarlyLintPass,
+        [
+            UnusedParens: UnusedParens,
+            UnusedBraces: UnusedBraces,
+            UnusedImportBraces: UnusedImportBraces,
+            UnsafeCode: UnsafeCode,
+            SpecialModuleName: SpecialModuleName,
+            AnonymousParameters: AnonymousParameters,
+            EllipsisInclusiveRangePatterns: EllipsisInclusiveRangePatterns::default(),
+            NonCamelCaseTypes: NonCamelCaseTypes,
+            DeprecatedAttr: DeprecatedAttr::new(),
+            WhileTrue: WhileTrue,
+            NonAsciiIdents: NonAsciiIdents,
+            HiddenUnicodeCodepoints: HiddenUnicodeCodepoints,
+            IncompleteFeatures: IncompleteFeatures,
+            RedundantSemicolons: RedundantSemicolons,
+            UnusedDocComment: UnusedDocComment,
+            UnexpectedCfgs: UnexpectedCfgs,
+        ]
+    ]
+);
+
+// FIXME: Make a separate lint type which does not require typeck tables.
+
+late_lint_methods!(
+    declare_combined_late_lint_pass,
+    [
+        pub BuiltinCombinedLateLintPass,
+        [
+            // Tracks state across modules
+            UnnameableTestItems: UnnameableTestItems::new(),
+            // Tracks attributes of parents
+            MissingDoc: MissingDoc::new(),
+            // Builds a global list of all impls of `Debug`.
+            // FIXME: Turn the computation of types which implement Debug into a query
+            // and change this to a module lint pass
+            MissingDebugImplementations: MissingDebugImplementations::default(),
+            // Keeps a global list of foreign declarations.
+            ClashingExternDeclarations: ClashingExternDeclarations::new(),
+        ]
+    ]
+);
+
+late_lint_methods!(
+    declare_combined_late_lint_pass,
+    [
+        BuiltinCombinedModuleLateLintPass,
+        [
+            ForLoopsOverFallibles: ForLoopsOverFallibles,
+            DerefIntoDynSupertrait: DerefIntoDynSupertrait,
+            HardwiredLints: HardwiredLints,
+            ImproperCTypesDeclarations: ImproperCTypesDeclarations,
+            ImproperCTypesDefinitions: ImproperCTypesDefinitions,
+            VariantSizeDifferences: VariantSizeDifferences,
+            BoxPointers: BoxPointers,
+            PathStatements: PathStatements,
+            LetUnderscore: LetUnderscore,
+            // Depends on referenced function signatures in expressions
+            UnusedResults: UnusedResults,
+            NonUpperCaseGlobals: NonUpperCaseGlobals,
+            NonShorthandFieldPatterns: NonShorthandFieldPatterns,
+            UnusedAllocation: UnusedAllocation,
+            // Depends on types used in type definitions
+            MissingCopyImplementations: MissingCopyImplementations,
+            // Depends on referenced function signatures in expressions
+            MutableTransmutes: MutableTransmutes,
+            TypeAliasBounds: TypeAliasBounds,
+            TrivialConstraints: TrivialConstraints,
+            TypeLimits: TypeLimits::new(),
+            NonSnakeCase: NonSnakeCase,
+            InvalidNoMangleItems: InvalidNoMangleItems,
+            // Depends on effective visibilities
+            UnreachablePub: UnreachablePub,
+            ExplicitOutlivesRequirements: ExplicitOutlivesRequirements,
+            InvalidValue: InvalidValue,
+            DerefNullPtr: DerefNullPtr,
+            // May Depend on constants elsewhere
+            UnusedBrokenConst: UnusedBrokenConst,
+            UnstableFeatures: UnstableFeatures,
+            ArrayIntoIter: ArrayIntoIter::default(),
+            DropTraitConstraints: DropTraitConstraints,
+            TemporaryCStringAsPtr: TemporaryCStringAsPtr,
+            NonPanicFmt: NonPanicFmt,
+            NoopMethodCall: NoopMethodCall,
+            EnumIntrinsicsNonEnums: EnumIntrinsicsNonEnums,
+            InvalidAtomicOrdering: InvalidAtomicOrdering,
+            NamedAsmLabels: NamedAsmLabels,
+            OpaqueHiddenInferredBound: OpaqueHiddenInferredBound,
+        ]
+    ]
+);
+
+pub fn new_lint_store(internal_lints: bool) -> LintStore {
     let mut lint_store = LintStore::new();
 
-    register_builtins(&mut lint_store, no_interleave_lints);
+    register_builtins(&mut lint_store);
     if internal_lints {
         register_internals(&mut lint_store);
     }
@@ -263,54 +246,17 @@ pub fn new_lint_store(no_interleave_lints: bool, internal_lints: bool) -> LintSt
 /// Tell the `LintStore` about all the built-in lints (the ones
 /// defined in this crate and the ones defined in
 /// `rustc_session::lint::builtin`).
-fn register_builtins(store: &mut LintStore, no_interleave_lints: bool) {
+fn register_builtins(store: &mut LintStore) {
     macro_rules! add_lint_group {
         ($name:expr, $($lint:ident),*) => (
             store.register_group(false, $name, None, vec![$(LintId::of($lint)),*]);
         )
     }
 
-    macro_rules! register_early_pass {
-        ($method:ident, $ty:ident, $constructor:expr) => {
-            store.register_lints(&$ty::get_lints());
-            store.$method(|| Box::new($constructor));
-        };
-    }
-
-    macro_rules! register_late_pass {
-        ($method:ident, $ty:ident, $constructor:expr) => {
-            store.register_lints(&$ty::get_lints());
-            store.$method(|_| Box::new($constructor));
-        };
-    }
-
-    macro_rules! register_early_passes {
-        ($method:ident, [$($passes:ident: $constructor:expr,)*]) => (
-            $(
-                register_early_pass!($method, $passes, $constructor);
-            )*
-        )
-    }
-
-    macro_rules! register_late_passes {
-        ($method:ident, [$($passes:ident: $constructor:expr,)*]) => (
-            $(
-                register_late_pass!($method, $passes, $constructor);
-            )*
-        )
-    }
-
-    if no_interleave_lints {
-        pre_expansion_lint_passes!(register_early_passes, register_pre_expansion_pass);
-        early_lint_passes!(register_early_passes, register_early_pass);
-        late_lint_passes!(register_late_passes, register_late_pass);
-        late_lint_mod_passes!(register_late_passes, register_late_mod_pass);
-    } else {
-        store.register_lints(&BuiltinCombinedPreExpansionLintPass::get_lints());
-        store.register_lints(&BuiltinCombinedEarlyLintPass::get_lints());
-        store.register_lints(&BuiltinCombinedModuleLateLintPass::get_lints());
-        store.register_lints(&BuiltinCombinedLateLintPass::get_lints());
-    }
+    store.register_lints(&BuiltinCombinedPreExpansionLintPass::get_lints());
+    store.register_lints(&BuiltinCombinedEarlyLintPass::get_lints());
+    store.register_lints(&BuiltinCombinedModuleLateLintPass::get_lints());
+    store.register_lints(&BuiltinCombinedLateLintPass::get_lints());
 
     add_lint_group!(
         "nonstandard_style",
index cf1d82f4c06e1077250baf0d70b4d53d7c7382cd..0fa81b7e4e0bc20f2c644783199734475e474359 100644 (file)
@@ -10,7 +10,7 @@
     /// The `rustc_pass_by_value` lint marks a type with `#[rustc_pass_by_value]` requiring it to
     /// always be passed by value. This is usually used for types that are thin wrappers around
     /// references, so there is no benefit to an extra layer of indirection. (Example: `Ty` which
-    /// is a reference to an `Interned<TyS>`)
+    /// is a reference to an `Interned<TyKind>`)
     pub rustc::PASS_BY_VALUE,
     Warn,
     "pass by reference of a type flagged as `#[rustc_pass_by_value]`",
index 1c6a057d1a85b56e3faf054f711aa52888572623..5558156a4b9ef040a07ff54271328b64f31e2ba4 100644 (file)
@@ -1,7 +1,6 @@
 use crate::context::{EarlyContext, LateContext};
 
 use rustc_ast as ast;
-use rustc_data_structures::sync;
 use rustc_hir as hir;
 use rustc_session::lint::builtin::HardwiredLints;
 use rustc_session::lint::LintPass;
 
 #[macro_export]
 macro_rules! late_lint_methods {
-    ($macro:path, $args:tt, [$hir:tt]) => (
-        $macro!($args, [$hir], [
-            fn check_body(a: &$hir hir::Body<$hir>);
-            fn check_body_post(a: &$hir hir::Body<$hir>);
+    ($macro:path, $args:tt) => (
+        $macro!($args, [
+            fn check_body(a: &'tcx hir::Body<'tcx>);
+            fn check_body_post(a: &'tcx hir::Body<'tcx>);
             fn check_crate();
             fn check_crate_post();
-            fn check_mod(a: &$hir hir::Mod<$hir>, b: hir::HirId);
-            fn check_foreign_item(a: &$hir hir::ForeignItem<$hir>);
-            fn check_item(a: &$hir hir::Item<$hir>);
-            fn check_item_post(a: &$hir hir::Item<$hir>);
-            fn check_local(a: &$hir hir::Local<$hir>);
-            fn check_block(a: &$hir hir::Block<$hir>);
-            fn check_block_post(a: &$hir hir::Block<$hir>);
-            fn check_stmt(a: &$hir hir::Stmt<$hir>);
-            fn check_arm(a: &$hir hir::Arm<$hir>);
-            fn check_pat(a: &$hir hir::Pat<$hir>);
-            fn check_expr(a: &$hir hir::Expr<$hir>);
-            fn check_expr_post(a: &$hir hir::Expr<$hir>);
-            fn check_ty(a: &$hir hir::Ty<$hir>);
-            fn check_generic_param(a: &$hir hir::GenericParam<$hir>);
-            fn check_generics(a: &$hir hir::Generics<$hir>);
-            fn check_poly_trait_ref(a: &$hir hir::PolyTraitRef<$hir>);
+            fn check_mod(a: &'tcx hir::Mod<'tcx>, b: hir::HirId);
+            fn check_foreign_item(a: &'tcx hir::ForeignItem<'tcx>);
+            fn check_item(a: &'tcx hir::Item<'tcx>);
+            fn check_item_post(a: &'tcx hir::Item<'tcx>);
+            fn check_local(a: &'tcx hir::Local<'tcx>);
+            fn check_block(a: &'tcx hir::Block<'tcx>);
+            fn check_block_post(a: &'tcx hir::Block<'tcx>);
+            fn check_stmt(a: &'tcx hir::Stmt<'tcx>);
+            fn check_arm(a: &'tcx hir::Arm<'tcx>);
+            fn check_pat(a: &'tcx hir::Pat<'tcx>);
+            fn check_expr(a: &'tcx hir::Expr<'tcx>);
+            fn check_expr_post(a: &'tcx hir::Expr<'tcx>);
+            fn check_ty(a: &'tcx hir::Ty<'tcx>);
+            fn check_generic_param(a: &'tcx hir::GenericParam<'tcx>);
+            fn check_generics(a: &'tcx hir::Generics<'tcx>);
+            fn check_poly_trait_ref(a: &'tcx hir::PolyTraitRef<'tcx>);
             fn check_fn(
-                a: rustc_hir::intravisit::FnKind<$hir>,
-                b: &$hir hir::FnDecl<$hir>,
-                c: &$hir hir::Body<$hir>,
+                a: rustc_hir::intravisit::FnKind<'tcx>,
+                b: &'tcx hir::FnDecl<'tcx>,
+                c: &'tcx hir::Body<'tcx>,
                 d: Span,
                 e: hir::HirId);
-            fn check_trait_item(a: &$hir hir::TraitItem<$hir>);
-            fn check_impl_item(a: &$hir hir::ImplItem<$hir>);
-            fn check_impl_item_post(a: &$hir hir::ImplItem<$hir>);
-            fn check_struct_def(a: &$hir hir::VariantData<$hir>);
-            fn check_field_def(a: &$hir hir::FieldDef<$hir>);
-            fn check_variant(a: &$hir hir::Variant<$hir>);
-            fn check_path(a: &$hir hir::Path<$hir>, b: hir::HirId);
-            fn check_attribute(a: &$hir ast::Attribute);
+            fn check_trait_item(a: &'tcx hir::TraitItem<'tcx>);
+            fn check_impl_item(a: &'tcx hir::ImplItem<'tcx>);
+            fn check_impl_item_post(a: &'tcx hir::ImplItem<'tcx>);
+            fn check_struct_def(a: &'tcx hir::VariantData<'tcx>);
+            fn check_field_def(a: &'tcx hir::FieldDef<'tcx>);
+            fn check_variant(a: &'tcx hir::Variant<'tcx>);
+            fn check_path(a: &hir::Path<'tcx>, b: hir::HirId);
+            fn check_attribute(a: &'tcx ast::Attribute);
 
             /// Called when entering a syntax node that can have lint attributes such
             /// as `#[allow(...)]`. Called with *all* the attributes of that node.
-            fn enter_lint_attrs(a: &$hir [ast::Attribute]);
+            fn enter_lint_attrs(a: &'tcx [ast::Attribute]);
 
             /// Counterpart to `enter_lint_attrs`.
-            fn exit_lint_attrs(a: &$hir [ast::Attribute]);
+            fn exit_lint_attrs(a: &'tcx [ast::Attribute]);
         ]);
     )
 }
@@ -66,28 +65,24 @@ fn check_fn(
 // FIXME: eliminate the duplication with `Visitor`. But this also
 // contains a few lint-specific methods with no equivalent in `Visitor`.
 
-macro_rules! expand_lint_pass_methods {
-    ($context:ty, [$($(#[$attr:meta])* fn $name:ident($($param:ident: $arg:ty),*);)*]) => (
-        $(#[inline(always)] fn $name(&mut self, _: $context, $(_: $arg),*) {})*
-    )
-}
-
 macro_rules! declare_late_lint_pass {
-    ([], [$hir:tt], [$($methods:tt)*]) => (
-        pub trait LateLintPass<$hir>: LintPass {
-            expand_lint_pass_methods!(&LateContext<$hir>, [$($methods)*]);
+    ([], [$($(#[$attr:meta])* fn $name:ident($($param:ident: $arg:ty),*);)*]) => (
+        pub trait LateLintPass<'tcx>: LintPass {
+            $(#[inline(always)] fn $name(&mut self, _: &LateContext<'tcx>, $(_: $arg),*) {})*
         }
     )
 }
 
-late_lint_methods!(declare_late_lint_pass, [], ['tcx]);
+// Declare the `LateLintPass` trait, which contains empty default definitions
+// for all the `check_*` methods.
+late_lint_methods!(declare_late_lint_pass, []);
 
 impl LateLintPass<'_> for HardwiredLints {}
 
 #[macro_export]
 macro_rules! expand_combined_late_lint_pass_method {
-    ([$($passes:ident),*], $self: ident, $name: ident, $params:tt) => ({
-        $($self.$passes.$name $params;)*
+    ([$($pass:ident),*], $self: ident, $name: ident, $params:tt) => ({
+        $($self.$pass.$name $params;)*
     })
 }
 
@@ -100,30 +95,35 @@ macro_rules! expand_combined_late_lint_pass_methods {
     )
 }
 
+/// Combines multiple lints passes into a single lint pass, at compile time,
+/// for maximum speed. Each `check_foo` method in `$methods` within this pass
+/// simply calls `check_foo` once per `$pass`. Compare with
+/// `LateLintPassObjects`, which is similar, but combines lint passes at
+/// runtime.
 #[macro_export]
 macro_rules! declare_combined_late_lint_pass {
-    ([$v:vis $name:ident, [$($passes:ident: $constructor:expr,)*]], [$hir:tt], $methods:tt) => (
+    ([$v:vis $name:ident, [$($pass:ident: $constructor:expr,)*]], $methods:tt) => (
         #[allow(non_snake_case)]
         $v struct $name {
-            $($passes: $passes,)*
+            $($pass: $pass,)*
         }
 
         impl $name {
             $v fn new() -> Self {
                 Self {
-                    $($passes: $constructor,)*
+                    $($pass: $constructor,)*
                 }
             }
 
             $v fn get_lints() -> LintArray {
                 let mut lints = Vec::new();
-                $(lints.extend_from_slice(&$passes::get_lints());)*
+                $(lints.extend_from_slice(&$pass::get_lints());)*
                 lints
             }
         }
 
         impl<'tcx> LateLintPass<'tcx> for $name {
-            expand_combined_late_lint_pass_methods!([$($passes),*], $methods);
+            expand_combined_late_lint_pass_methods!([$($pass),*], $methods);
         }
 
         #[allow(rustc::lint_pass_impl_without_macro)]
@@ -175,26 +175,22 @@ macro_rules! early_lint_methods {
     )
 }
 
-macro_rules! expand_early_lint_pass_methods {
-    ($context:ty, [$($(#[$attr:meta])* fn $name:ident($($param:ident: $arg:ty),*);)*]) => (
-        $(#[inline(always)] fn $name(&mut self, _: $context, $(_: $arg),*) {})*
-    )
-}
-
 macro_rules! declare_early_lint_pass {
-    ([], [$($methods:tt)*]) => (
+    ([], [$($(#[$attr:meta])* fn $name:ident($($param:ident: $arg:ty),*);)*]) => (
         pub trait EarlyLintPass: LintPass {
-            expand_early_lint_pass_methods!(&EarlyContext<'_>, [$($methods)*]);
+            $(#[inline(always)] fn $name(&mut self, _: &EarlyContext<'_>, $(_: $arg),*) {})*
         }
     )
 }
 
+// Declare the `EarlyLintPass` trait, which contains empty default definitions
+// for all the `check_*` methods.
 early_lint_methods!(declare_early_lint_pass, []);
 
 #[macro_export]
 macro_rules! expand_combined_early_lint_pass_method {
-    ([$($passes:ident),*], $self: ident, $name: ident, $params:tt) => ({
-        $($self.$passes.$name $params;)*
+    ([$($pass:ident),*], $self: ident, $name: ident, $params:tt) => ({
+        $($self.$pass.$name $params;)*
     })
 }
 
@@ -207,30 +203,35 @@ macro_rules! expand_combined_early_lint_pass_methods {
     )
 }
 
+/// Combines multiple lints passes into a single lint pass, at compile time,
+/// for maximum speed. Each `check_foo` method in `$methods` within this pass
+/// simply calls `check_foo` once per `$pass`. Compare with
+/// `EarlyLintPassObjects`, which is similar, but combines lint passes at
+/// runtime.
 #[macro_export]
 macro_rules! declare_combined_early_lint_pass {
-    ([$v:vis $name:ident, [$($passes:ident: $constructor:expr,)*]], $methods:tt) => (
+    ([$v:vis $name:ident, [$($pass:ident: $constructor:expr,)*]], $methods:tt) => (
         #[allow(non_snake_case)]
         $v struct $name {
-            $($passes: $passes,)*
+            $($pass: $pass,)*
         }
 
         impl $name {
             $v fn new() -> Self {
                 Self {
-                    $($passes: $constructor,)*
+                    $($pass: $constructor,)*
                 }
             }
 
             $v fn get_lints() -> LintArray {
                 let mut lints = Vec::new();
-                $(lints.extend_from_slice(&$passes::get_lints());)*
+                $(lints.extend_from_slice(&$pass::get_lints());)*
                 lints
             }
         }
 
         impl EarlyLintPass for $name {
-            expand_combined_early_lint_pass_methods!([$($passes),*], $methods);
+            expand_combined_early_lint_pass_methods!([$($pass),*], $methods);
         }
 
         #[allow(rustc::lint_pass_impl_without_macro)]
@@ -243,5 +244,5 @@ fn name(&self) -> &'static str {
 }
 
 /// A lint pass boxed up as a trait object.
-pub type EarlyLintPassObject = Box<dyn EarlyLintPass + sync::Send + 'static>;
-pub type LateLintPassObject<'tcx> = Box<dyn LateLintPass<'tcx> + sync::Send + 'tcx>;
+pub type EarlyLintPassObject = Box<dyn EarlyLintPass + 'static>;
+pub type LateLintPassObject<'tcx> = Box<dyn LateLintPass<'tcx> + 'tcx>;
index 297b509d4023d40138c47233316a38c2e41270e6..8446da6098ee9641764fa423412368ebbbd524c4 100644 (file)
@@ -16,7 +16,6 @@
 use rustc_target::abi::{Integer, TagEncoding, Variants};
 use rustc_target::spec::abi::Abi as SpecAbi;
 
-use std::cmp;
 use std::iter;
 use std::ops::ControlFlow;
 
@@ -531,7 +530,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx hir::Expr<'tcx>) {
             _ => {}
         };
 
-        fn is_valid<T: cmp::PartialOrd>(binop: hir::BinOp, v: T, min: T, max: T) -> bool {
+        fn is_valid<T: PartialOrd>(binop: hir::BinOp, v: T, min: T, max: T) -> bool {
             match binop.node {
                 hir::BinOpKind::Lt => v > min && v <= max,
                 hir::BinOpKind::Le => v >= min && v < max,
index 88ad4c67d93e4e80119ddf417c2204f38f6c01cd..dc352778f1d1bcdab92dea9ea4f68f698fc02f2e 100644 (file)
@@ -617,7 +617,10 @@ fn is_expr_delims_necessary(
         lhs_needs_parens
             || (followed_by_block
                 && match &inner.kind {
-                    ExprKind::Ret(_) | ExprKind::Break(..) | ExprKind::Yield(..) => true,
+                    ExprKind::Ret(_)
+                    | ExprKind::Break(..)
+                    | ExprKind::Yield(..)
+                    | ExprKind::Yeet(..) => true,
                     ExprKind::Range(_lhs, Some(rhs), _limits) => {
                         matches!(rhs.kind, ExprKind::Block(..))
                     }
@@ -633,13 +636,34 @@ fn emit_unused_delims_expr(
         left_pos: Option<BytePos>,
         right_pos: Option<BytePos>,
     ) {
+        // If `value` has `ExprKind::Err`, unused delim lint can be broken.
+        // For example, the following code caused ICE.
+        // This is because the `ExprKind::Call` in `value` has `ExprKind::Err` as its argument
+        // and this leads to wrong spans. #104897
+        //
+        // ```
+        // fn f(){(print!(á
+        // ```
+        use rustc_ast::visit::{walk_expr, Visitor};
+        struct ErrExprVisitor {
+            has_error: bool,
+        }
+        impl<'ast> Visitor<'ast> for ErrExprVisitor {
+            fn visit_expr(&mut self, expr: &'ast ast::Expr) {
+                if let ExprKind::Err = expr.kind {
+                    self.has_error = true;
+                    return;
+                }
+                walk_expr(self, expr)
+            }
+        }
+        let mut visitor = ErrExprVisitor { has_error: false };
+        visitor.visit_expr(value);
+        if visitor.has_error {
+            return;
+        }
         let spans = match value.kind {
             ast::ExprKind::Block(ref block, None) if block.stmts.len() == 1 => {
-                if let StmtKind::Expr(expr) = &block.stmts[0].kind
-                    && let ExprKind::Err = expr.kind
-                {
-                    return
-                }
                 if let Some(span) = block.stmts[0].span.find_ancestor_inside(value.span) {
                     Some((value.span.with_hi(span.lo()), value.span.with_lo(span.hi())))
                 } else {
@@ -925,6 +949,7 @@ fn check_unused_parens_pat(
 }
 
 impl EarlyLintPass for UnusedParens {
+    #[inline]
     fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &ast::Expr) {
         match e.kind {
             ExprKind::Let(ref pat, _, _) | ExprKind::ForLoop(ref pat, ..) => {
@@ -1143,6 +1168,7 @@ fn check_stmt(&mut self, cx: &EarlyContext<'_>, s: &ast::Stmt) {
         <Self as UnusedDelimLint>::check_stmt(self, cx, s)
     }
 
+    #[inline]
     fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &ast::Expr) {
         <Self as UnusedDelimLint>::check_expr(self, cx, e);
 
@@ -1264,7 +1290,7 @@ fn check_use_tree(&self, cx: &EarlyContext<'_>, use_tree: &ast::UseTree, item: &
 
             // Trigger the lint if the nested item is a non-self single item
             let node_name = match items[0].0.kind {
-                ast::UseTreeKind::Simple(rename, ..) => {
+                ast::UseTreeKind::Simple(rename) => {
                     let orig_ident = items[0].0.prefix.segments.last().unwrap().ident;
                     if orig_ident.name == kw::SelfLower {
                         return;
index d35e4191cc0b1dfc1ae36d59caf4e74556a6997c..0b3c057345a67d9a532e4b15e041f353b88f1743 100644 (file)
@@ -222,6 +222,7 @@ fn main() {
         .file("llvm-wrapper/RustWrapper.cpp")
         .file("llvm-wrapper/ArchiveWrapper.cpp")
         .file("llvm-wrapper/CoverageMappingWrapper.cpp")
+        .file("llvm-wrapper/SymbolWrapper.cpp")
         .file("llvm-wrapper/Linker.cpp")
         .cpp(true)
         .cpp_link_stdlib(None) // we handle this below
@@ -237,18 +238,20 @@ fn main() {
 
     if !is_crossed {
         cmd.arg("--system-libs");
-    } else if target.contains("windows-gnu") {
-        println!("cargo:rustc-link-lib=shell32");
-        println!("cargo:rustc-link-lib=uuid");
-    } else if target.contains("netbsd") || target.contains("haiku") || target.contains("darwin") {
-        println!("cargo:rustc-link-lib=z");
-    } else if target.starts_with("arm")
+    }
+
+    if (target.starts_with("arm") && !target.contains("freebsd"))
         || target.starts_with("mips-")
         || target.starts_with("mipsel-")
         || target.starts_with("powerpc-")
     {
         // 32-bit targets need to link libatomic.
         println!("cargo:rustc-link-lib=atomic");
+    } else if target.contains("windows-gnu") {
+        println!("cargo:rustc-link-lib=shell32");
+        println!("cargo:rustc-link-lib=uuid");
+    } else if target.contains("netbsd") || target.contains("haiku") || target.contains("darwin") {
+        println!("cargo:rustc-link-lib=z");
     }
     cmd.args(&components);
 
index 7f4d63eed8bdf225c8e3ea7ea7d3a17a80f790ed..2865ea8927336143490193bddbeaec125dda6789 100644 (file)
@@ -205,7 +205,12 @@ enum class LLVMRustCodeModel {
   None,
 };
 
-static Optional<CodeModel::Model> fromRust(LLVMRustCodeModel Model) {
+#if LLVM_VERSION_LT(16, 0)
+static Optional<CodeModel::Model>
+#else
+static std::optional<CodeModel::Model>
+#endif
+fromRust(LLVMRustCodeModel Model) {
   switch (Model) {
   case LLVMRustCodeModel::Tiny:
     return CodeModel::Tiny;
@@ -218,7 +223,11 @@ static Optional<CodeModel::Model> fromRust(LLVMRustCodeModel Model) {
   case LLVMRustCodeModel::Large:
     return CodeModel::Large;
   case LLVMRustCodeModel::None:
+#if LLVM_VERSION_LT(16, 0)
     return None;
+#else
+    return std::nullopt;
+#endif
   default:
     report_fatal_error("Bad CodeModel.");
   }
@@ -638,7 +647,11 @@ LLVMRustOptimize(
     LLVMSelfProfileInitializeCallbacks(PIC,LlvmSelfProfiler,BeforePassCallback,AfterPassCallback);
   }
 
+#if LLVM_VERSION_LT(16, 0)
   Optional<PGOOptions> PGOOpt;
+#else
+  std::optional<PGOOptions> PGOOpt;
+#endif
   if (PGOGenPath) {
     assert(!PGOUsePath && !PGOSampleUsePath);
     PGOOpt = PGOOptions(PGOGenPath, "", "", PGOOptions::IRInstr,
index 216c35d6da078fb629c6bba3b02333bd6807dc3f..279b699185421982026fad27f12804d00a8e7d8d 100644 (file)
@@ -17,7 +17,9 @@
 #include "llvm/Pass.h"
 #include "llvm/Bitcode/BitcodeWriter.h"
 #include "llvm/Support/Signals.h"
+#if LLVM_VERSION_LT(16, 0)
 #include "llvm/ADT/Optional.h"
+#endif
 
 #include <iostream>
 
@@ -320,7 +322,13 @@ extern "C" LLVMAttributeRef LLVMRustCreateUWTableAttr(LLVMContextRef C, bool Asy
 }
 
 extern "C" LLVMAttributeRef LLVMRustCreateAllocSizeAttr(LLVMContextRef C, uint32_t ElementSizeArg) {
-  return wrap(Attribute::getWithAllocSizeArgs(*unwrap(C), ElementSizeArg, None));
+  return wrap(Attribute::getWithAllocSizeArgs(*unwrap(C), ElementSizeArg,
+#if LLVM_VERSION_LT(16, 0)
+                                              None
+#else
+                                              std::nullopt
+#endif
+                                              ));
 }
 
 #if LLVM_VERSION_GE(15, 0)
@@ -708,10 +716,18 @@ enum class LLVMRustChecksumKind {
   SHA256,
 };
 
+#if LLVM_VERSION_LT(16, 0)
 static Optional<DIFile::ChecksumKind> fromRust(LLVMRustChecksumKind Kind) {
+#else
+static std::optional<DIFile::ChecksumKind> fromRust(LLVMRustChecksumKind Kind) {
+#endif
   switch (Kind) {
   case LLVMRustChecksumKind::None:
+#if LLVM_VERSION_LT(16, 0)
     return None;
+#else
+    return std::nullopt;
+#endif
   case LLVMRustChecksumKind::MD5:
     return DIFile::ChecksumKind::CSK_MD5;
   case LLVMRustChecksumKind::SHA1:
@@ -787,8 +803,18 @@ extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateFile(
     const char *Filename, size_t FilenameLen,
     const char *Directory, size_t DirectoryLen, LLVMRustChecksumKind CSKind,
     const char *Checksum, size_t ChecksumLen) {
+
+#if LLVM_VERSION_LT(16, 0)
   Optional<DIFile::ChecksumKind> llvmCSKind = fromRust(CSKind);
+#else
+  std::optional<DIFile::ChecksumKind> llvmCSKind = fromRust(CSKind);
+#endif
+
+#if LLVM_VERSION_LT(16, 0)
   Optional<DIFile::ChecksumInfo<StringRef>> CSInfo{};
+#else
+  std::optional<DIFile::ChecksumInfo<StringRef>> CSInfo{};
+#endif
   if (llvmCSKind)
     CSInfo.emplace(*llvmCSKind, StringRef{Checksum, ChecksumLen});
   return wrap(Builder->createFile(StringRef(Filename, FilenameLen),
@@ -1460,13 +1486,13 @@ extern "C" void LLVMRustFreeOperandBundleDef(OperandBundleDef *Bundle) {
 
 extern "C" LLVMValueRef LLVMRustBuildCall(LLVMBuilderRef B, LLVMTypeRef Ty, LLVMValueRef Fn,
                                           LLVMValueRef *Args, unsigned NumArgs,
-                                          OperandBundleDef *Bundle) {
+                                          OperandBundleDef **OpBundles,
+                                          unsigned NumOpBundles) {
   Value *Callee = unwrap(Fn);
   FunctionType *FTy = unwrap<FunctionType>(Ty);
-  unsigned Len = Bundle ? 1 : 0;
-  ArrayRef<OperandBundleDef> Bundles = makeArrayRef(Bundle, Len);
   return wrap(unwrap(B)->CreateCall(
-      FTy, Callee, makeArrayRef(unwrap(Args), NumArgs), Bundles));
+      FTy, Callee, makeArrayRef(unwrap(Args), NumArgs),
+      makeArrayRef(*OpBundles, NumOpBundles)));
 }
 
 extern "C" LLVMValueRef LLVMRustGetInstrProfIncrementIntrinsic(LLVMModuleRef M) {
@@ -1506,14 +1532,14 @@ extern "C" LLVMValueRef
 LLVMRustBuildInvoke(LLVMBuilderRef B, LLVMTypeRef Ty, LLVMValueRef Fn,
                     LLVMValueRef *Args, unsigned NumArgs,
                     LLVMBasicBlockRef Then, LLVMBasicBlockRef Catch,
-                    OperandBundleDef *Bundle, const char *Name) {
+                    OperandBundleDef **OpBundles, unsigned NumOpBundles,
+                    const char *Name) {
   Value *Callee = unwrap(Fn);
   FunctionType *FTy = unwrap<FunctionType>(Ty);
-  unsigned Len = Bundle ? 1 : 0;
-  ArrayRef<OperandBundleDef> Bundles = makeArrayRef(Bundle, Len);
   return wrap(unwrap(B)->CreateInvoke(FTy, Callee, unwrap(Then), unwrap(Catch),
                                       makeArrayRef(unwrap(Args), NumArgs),
-                                      Bundles, Name));
+                                      makeArrayRef(*OpBundles, NumOpBundles),
+                                      Name));
 }
 
 extern "C" void LLVMRustPositionBuilderAtStart(LLVMBuilderRef B,
@@ -1967,3 +1993,7 @@ extern "C" int32_t LLVMRustGetElementTypeArgIndex(LLVMValueRef CallSite) {
 #endif
     return -1;
 }
+
+extern "C" bool LLVMRustIsBitcode(char *ptr, size_t len) {
+  return identify_magic(StringRef(ptr, len)) == file_magic::bitcode;
+}
diff --git a/compiler/rustc_llvm/llvm-wrapper/SymbolWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/SymbolWrapper.cpp
new file mode 100644 (file)
index 0000000..974207e
--- /dev/null
@@ -0,0 +1,96 @@
+// Derived from code in LLVM, which is:
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+// Derived from:
+// * https://github.com/llvm/llvm-project/blob/8ef3e895ad8ab1724e2b87cabad1dacdc7a397a3/llvm/include/llvm/Object/ArchiveWriter.h
+// * https://github.com/llvm/llvm-project/blob/8ef3e895ad8ab1724e2b87cabad1dacdc7a397a3/llvm/lib/Object/ArchiveWriter.cpp
+
+#include "llvm/IR/LLVMContext.h"
+#include "llvm/Object/ObjectFile.h"
+#include "llvm/ADT/Optional.h"
+
+using namespace llvm;
+using namespace llvm::sys;
+using namespace llvm::object;
+
+static bool isArchiveSymbol(const object::BasicSymbolRef &S) {
+  Expected<uint32_t> SymFlagsOrErr = S.getFlags();
+  if (!SymFlagsOrErr)
+    // FIXME: Actually report errors helpfully.
+    report_fatal_error(SymFlagsOrErr.takeError());
+  if (*SymFlagsOrErr & object::SymbolRef::SF_FormatSpecific)
+    return false;
+  if (!(*SymFlagsOrErr & object::SymbolRef::SF_Global))
+    return false;
+  if (*SymFlagsOrErr & object::SymbolRef::SF_Undefined)
+    return false;
+  return true;
+}
+
+typedef void *(*LLVMRustGetSymbolsCallback)(void *, const char *);
+typedef void *(*LLVMRustGetSymbolsErrorCallback)(const char *);
+
+// Note: This is implemented in C++ instead of using the C api from Rust as IRObjectFile doesn't
+// implement getSymbolName, only printSymbolName, which is inaccessible from the C api.
+extern "C" void *LLVMRustGetSymbols(
+  char *BufPtr, size_t BufLen, void *State, LLVMRustGetSymbolsCallback Callback,
+  LLVMRustGetSymbolsErrorCallback ErrorCallback) {
+  std::unique_ptr<MemoryBuffer> Buf =
+    MemoryBuffer::getMemBuffer(StringRef(BufPtr, BufLen), StringRef("LLVMRustGetSymbolsObject"),
+                               false);
+  SmallString<0> SymNameBuf;
+  raw_svector_ostream SymName(SymNameBuf);
+
+  // In the scenario when LLVMContext is populated SymbolicFile will contain a
+  // reference to it, thus SymbolicFile should be destroyed first.
+  LLVMContext Context;
+  std::unique_ptr<object::SymbolicFile> Obj;
+
+  const file_magic Type = identify_magic(Buf->getBuffer());
+  if (!object::SymbolicFile::isSymbolicFile(Type, &Context)) {
+    return 0;
+  }
+
+  if (Type == file_magic::bitcode) {
+    auto ObjOrErr = object::SymbolicFile::createSymbolicFile(
+      Buf->getMemBufferRef(), file_magic::bitcode, &Context);
+    if (!ObjOrErr) {
+      Error E = ObjOrErr.takeError();
+      SmallString<0> ErrorBuf;
+      raw_svector_ostream Error(ErrorBuf);
+      Error << E << '\0';
+      return ErrorCallback(Error.str().data());
+    }
+    Obj = std::move(*ObjOrErr);
+  } else {
+    auto ObjOrErr = object::SymbolicFile::createSymbolicFile(Buf->getMemBufferRef());
+    if (!ObjOrErr) {
+      Error E = ObjOrErr.takeError();
+      SmallString<0> ErrorBuf;
+      raw_svector_ostream Error(ErrorBuf);
+      Error << E << '\0';
+      return ErrorCallback(Error.str().data());
+    }
+    Obj = std::move(*ObjOrErr);
+  }
+
+
+  for (const object::BasicSymbolRef &S : Obj->symbols()) {
+    if (!isArchiveSymbol(S))
+      continue;
+    if (Error E = S.printName(SymName)) {
+      SmallString<0> ErrorBuf;
+      raw_svector_ostream Error(ErrorBuf);
+      Error << E << '\0';
+      return ErrorCallback(Error.str().data());
+    }
+    SymName << '\0';
+    if (void *E = Callback(State, SymNameBuf.str().data())) {
+      return E;
+    }
+    SymNameBuf.clear();
+  }
+  return 0;
+}
index be9821c00f507abd5f96bc349ac8f8c27ccb3657..684835d8c5c86b88e60713d8639ab1962a4eb0da 100644 (file)
@@ -29,8 +29,8 @@ pub(crate) fn into_tokens(self) -> TokenStream {
         let DiagnosticDerive { mut structure, mut builder } = self;
 
         let implementation = builder.each_variant(&mut structure, |mut builder, variant| {
-            let preamble = builder.preamble(&variant);
-            let body = builder.body(&variant);
+            let preamble = builder.preamble(variant);
+            let body = builder.body(variant);
 
             let diag = &builder.parent.diag;
             let DiagnosticDeriveKind::Diagnostic { handler } = &builder.parent.kind else {
@@ -39,7 +39,7 @@ pub(crate) fn into_tokens(self) -> TokenStream {
             let init = match builder.slug.value_ref() {
                 None => {
                     span_err(builder.span, "diagnostic slug not specified")
-                        .help(&format!(
+                        .help(format!(
                             "specify the slug as the first argument to the `#[diag(...)]` \
                             attribute, such as `#[diag(hir_analysis_example_error)]`",
                         ))
@@ -48,10 +48,10 @@ pub(crate) fn into_tokens(self) -> TokenStream {
                 }
                 Some(slug) if let Some( Mismatch { slug_name, crate_name, slug_prefix }) = Mismatch::check(slug) => {
                     span_err(slug.span().unwrap(), "diagnostic slug and crate name do not match")
-                        .note(&format!(
+                        .note(format!(
                             "slug is `{slug_name}` but the crate name is `{crate_name}`"
                         ))
-                        .help(&format!(
+                        .help(format!(
                             "expected a slug starting with `{slug_prefix}_...`"
                         ))
                         .emit();
@@ -113,8 +113,8 @@ pub(crate) fn into_tokens(self) -> TokenStream {
         let LintDiagnosticDerive { mut structure, mut builder } = self;
 
         let implementation = builder.each_variant(&mut structure, |mut builder, variant| {
-            let preamble = builder.preamble(&variant);
-            let body = builder.body(&variant);
+            let preamble = builder.preamble(variant);
+            let body = builder.body(variant);
 
             let diag = &builder.parent.diag;
             let formatting_init = &builder.formatting_init;
@@ -128,28 +128,28 @@ pub(crate) fn into_tokens(self) -> TokenStream {
 
         let msg = builder.each_variant(&mut structure, |mut builder, variant| {
             // Collect the slug by generating the preamble.
-            let _ = builder.preamble(&variant);
+            let _ = builder.preamble(variant);
 
             match builder.slug.value_ref() {
                 None => {
                     span_err(builder.span, "diagnostic slug not specified")
-                        .help(&format!(
+                        .help(format!(
                             "specify the slug as the first argument to the attribute, such as \
                             `#[diag(compiletest_example)]`",
                         ))
                         .emit();
-                    return DiagnosticDeriveError::ErrorHandled.to_compile_error();
+                    DiagnosticDeriveError::ErrorHandled.to_compile_error()
                 }
                 Some(slug) if let Some( Mismatch { slug_name, crate_name, slug_prefix }) = Mismatch::check(slug) => {
                     span_err(slug.span().unwrap(), "diagnostic slug and crate name do not match")
-                        .note(&format!(
+                        .note(format!(
                             "slug is `{slug_name}` but the crate name is `{crate_name}`"
                         ))
-                        .help(&format!(
+                        .help(format!(
                             "expected a slug starting with `{slug_prefix}_...`"
                         ))
                         .emit();
-                    return DiagnosticDeriveError::ErrorHandled.to_compile_error();
+                    DiagnosticDeriveError::ErrorHandled.to_compile_error()
                 }
                 Some(slug) => {
                     quote! {
index 3ea83fd09c794d5092586afe89cdc70a76be9fe5..9f2ac5112f1cd9d3aa4b78a9cf1deeda1c0ae799 100644 (file)
@@ -100,7 +100,7 @@ pub fn each_variant<'s, F>(&mut self, structure: &mut Structure<'s>, f: F) -> To
                 _ => variant.ast().ident.span().unwrap(),
             };
             let builder = DiagnosticDeriveVariantBuilder {
-                parent: &self,
+                parent: self,
                 span,
                 field_map: build_field_mapping(variant),
                 formatting_init: TokenStream::new(),
@@ -211,7 +211,7 @@ fn generate_structure_code_for_attr(
                     nested_iter.next();
                 }
                 Some(NestedMeta::Meta(Meta::NameValue { .. })) => {}
-                Some(nested_attr) => throw_invalid_nested_attr!(attr, &nested_attr, |diag| diag
+                Some(nested_attr) => throw_invalid_nested_attr!(attr, nested_attr, |diag| diag
                     .help("a diagnostic slug is required as the first argument")),
                 None => throw_invalid_attr!(attr, &meta, |diag| diag
                     .help("a diagnostic slug is required as the first argument")),
@@ -227,13 +227,13 @@ fn generate_structure_code_for_attr(
                         ..
                     })) => (value, path),
                     NestedMeta::Meta(Meta::Path(_)) => {
-                        invalid_nested_attr(attr, &nested_attr)
+                        invalid_nested_attr(attr, nested_attr)
                             .help("diagnostic slug must be the first argument")
                             .emit();
                         continue;
                     }
                     _ => {
-                        invalid_nested_attr(attr, &nested_attr).emit();
+                        invalid_nested_attr(attr, nested_attr).emit();
                         continue;
                     }
                 };
@@ -251,7 +251,7 @@ fn generate_structure_code_for_attr(
                             #diag.code(rustc_errors::DiagnosticId::Error(#code.to_string()));
                         });
                     }
-                    _ => invalid_nested_attr(attr, &nested_attr)
+                    _ => invalid_nested_attr(attr, nested_attr)
                         .help("only `code` is a valid nested attributes following the slug")
                         .emit(),
                 }
@@ -427,9 +427,9 @@ fn generate_inner_field_code(
                 Ok(self.add_spanned_subdiagnostic(binding, &fn_ident, slug))
             }
             SubdiagnosticKind::Note | SubdiagnosticKind::Help | SubdiagnosticKind::Warn => {
-                if type_matches_path(&info.ty, &["rustc_span", "Span"]) {
+                if type_matches_path(info.ty, &["rustc_span", "Span"]) {
                     Ok(self.add_spanned_subdiagnostic(binding, &fn_ident, slug))
-                } else if type_is_unit(&info.ty) {
+                } else if type_is_unit(info.ty) {
                     Ok(self.add_subdiagnostic(&fn_ident, slug))
                 } else {
                     report_type_error(attr, "`Span` or `()`")?
index fa0ca5a52423af786b2c53bce1e4d6cf6a60874b..446aebe4f83f59a3d95a4903227bd4fa7b9cbb92 100644 (file)
@@ -409,7 +409,7 @@ fn generate_field_code_inner_list(
                 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);
+                        throw_invalid_nested_attr!(attr, nested_attr);
                     };
 
                     let span = meta.span().unwrap();
@@ -427,7 +427,7 @@ fn generate_field_code_inner_list(
                             );
                             code.set_once((code_field, formatting_init), span);
                         }
-                        _ => throw_invalid_nested_attr!(attr, &nested_attr, |diag| {
+                        _ => throw_invalid_nested_attr!(attr, nested_attr, |diag| {
                             diag.help("`code` is the only valid nested attribute")
                         }),
                     }
index dff088b9bdfa66140867a8cc88f7e400a6c29961..da90233523ca3c83e503f45bb351207bcdcd5f74 100644 (file)
@@ -80,7 +80,7 @@ fn report_error_if_not_applied_to_ty(
     path: &[&str],
     ty_name: &str,
 ) -> Result<(), DiagnosticDeriveError> {
-    if !type_matches_path(&info.ty, path) {
+    if !type_matches_path(info.ty, path) {
         report_type_error(attr, ty_name)?;
     }
 
@@ -105,8 +105,8 @@ pub(crate) fn report_error_if_not_applied_to_span(
     attr: &Attribute,
     info: &FieldInfo<'_>,
 ) -> Result<(), DiagnosticDeriveError> {
-    if !type_matches_path(&info.ty, &["rustc_span", "Span"])
-        && !type_matches_path(&info.ty, &["rustc_errors", "MultiSpan"])
+    if !type_matches_path(info.ty, &["rustc_span", "Span"])
+        && !type_matches_path(info.ty, &["rustc_errors", "MultiSpan"])
     {
         report_type_error(attr, "`Span` or `MultiSpan`")?;
     }
@@ -686,7 +686,7 @@ pub(super) fn from_attr(
             let meta = match nested_attr {
                 NestedMeta::Meta(ref meta) => meta,
                 NestedMeta::Lit(_) => {
-                    invalid_nested_attr(attr, &nested_attr).emit();
+                    invalid_nested_attr(attr, nested_attr).emit();
                     continue;
                 }
             };
@@ -698,7 +698,7 @@ pub(super) fn from_attr(
             let string_value = match meta {
                 Meta::NameValue(MetaNameValue { lit: syn::Lit::Str(value), .. }) => Some(value),
 
-                Meta::Path(_) => throw_invalid_nested_attr!(attr, &nested_attr, |diag| {
+                Meta::Path(_) => throw_invalid_nested_attr!(attr, nested_attr, |diag| {
                     diag.help("a diagnostic slug must be the first argument to the attribute")
                 }),
                 _ => None,
@@ -720,7 +720,7 @@ pub(super) fn from_attr(
                     | SubdiagnosticKind::MultipartSuggestion { ref mut applicability, .. },
                 ) => {
                     let Some(value) = string_value else {
-                        invalid_nested_attr(attr, &nested_attr).emit();
+                        invalid_nested_attr(attr, nested_attr).emit();
                         continue;
                     };
 
@@ -736,7 +736,7 @@ pub(super) fn from_attr(
                     | SubdiagnosticKind::MultipartSuggestion { .. },
                 ) => {
                     let Some(value) = string_value else {
-                        invalid_nested_attr(attr, &nested_attr).emit();
+                        invalid_nested_attr(attr, nested_attr).emit();
                         continue;
                     };
 
@@ -752,19 +752,19 @@ pub(super) fn from_attr(
 
                 // Invalid nested attribute
                 (_, SubdiagnosticKind::Suggestion { .. }) => {
-                    invalid_nested_attr(attr, &nested_attr)
+                    invalid_nested_attr(attr, nested_attr)
                         .help(
                             "only `style`, `code` and `applicability` are valid nested attributes",
                         )
                         .emit();
                 }
                 (_, SubdiagnosticKind::MultipartSuggestion { .. }) => {
-                    invalid_nested_attr(attr, &nested_attr)
+                    invalid_nested_attr(attr, nested_attr)
                         .help("only `style` and `applicability` are valid nested attributes")
                         .emit()
                 }
                 _ => {
-                    invalid_nested_attr(attr, &nested_attr).emit();
+                    invalid_nested_attr(attr, nested_attr).emit();
                 }
             }
         }
index 4047969724aa93bcca3ea9e9a9a54f45f2b26e9d..789d83a0dd00d496f39eeee157d924d6f3cfd31b 100644 (file)
@@ -364,10 +364,6 @@ macro_rules! passthrough {
                 modifiers.eval_always.is_none(),
                 "Query {name} cannot be both `feedable` and `eval_always`."
             );
-            assert!(
-                modifiers.no_hash.is_none(),
-                "Query {name} cannot be both `feedable` and `no_hash`."
-            );
             feedable_queries.extend(quote! {
                 #(#doc_comments)*
                 [#attribute_stream] fn #name(#arg) #result,
index 1a2389c7a8448878b28c406dbe0d247a6b3a1a61..01d7f3e03c50a5520d5c4d5f3efe1bd8a7d67d9d 100644 (file)
@@ -13,7 +13,7 @@
 use rustc_ast::{self as ast, *};
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_data_structures::svh::Svh;
-use rustc_data_structures::sync::Lrc;
+use rustc_data_structures::sync::{Lrc, ReadGuard};
 use rustc_expand::base::SyntaxExtension;
 use rustc_hir::def_id::{CrateNum, LocalDefId, StableCrateId, LOCAL_CRATE};
 use rustc_hir::definitions::Definitions;
@@ -68,11 +68,12 @@ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 pub struct CrateLoader<'a> {
     // Immutable configuration.
     sess: &'a Session,
-    metadata_loader: Box<MetadataLoaderDyn>,
+    metadata_loader: &'a MetadataLoaderDyn,
+    definitions: ReadGuard<'a, Definitions>,
     local_crate_name: Symbol,
     // Mutable output.
-    cstore: CStore,
-    used_extern_options: FxHashSet<Symbol>,
+    cstore: &'a mut CStore,
+    used_extern_options: &'a mut FxHashSet<Symbol>,
 }
 
 pub enum LoadedMacro {
@@ -239,47 +240,49 @@ pub fn report_unused_deps(&self, tcx: TyCtxt<'_>) {
             );
         }
     }
+
+    pub fn new(sess: &Session) -> CStore {
+        let mut stable_crate_ids = FxHashMap::default();
+        stable_crate_ids.insert(sess.local_stable_crate_id(), LOCAL_CRATE);
+        CStore {
+            // We add an empty entry for LOCAL_CRATE (which maps to zero) in
+            // order to make array indices in `metas` match with the
+            // corresponding `CrateNum`. This first entry will always remain
+            // `None`.
+            metas: IndexVec::from_elem_n(None, 1),
+            injected_panic_runtime: None,
+            allocator_kind: None,
+            alloc_error_handler_kind: None,
+            has_global_allocator: false,
+            has_alloc_error_handler: false,
+            stable_crate_ids,
+            unused_externs: Vec::new(),
+        }
+    }
 }
 
 impl<'a> CrateLoader<'a> {
     pub fn new(
         sess: &'a Session,
-        metadata_loader: Box<MetadataLoaderDyn>,
-        local_crate_name: &str,
+        metadata_loader: &'a MetadataLoaderDyn,
+        local_crate_name: Symbol,
+        cstore: &'a mut CStore,
+        definitions: ReadGuard<'a, Definitions>,
+        used_extern_options: &'a mut FxHashSet<Symbol>,
     ) -> Self {
-        let mut stable_crate_ids = FxHashMap::default();
-        stable_crate_ids.insert(sess.local_stable_crate_id(), LOCAL_CRATE);
-
         CrateLoader {
             sess,
             metadata_loader,
-            local_crate_name: Symbol::intern(local_crate_name),
-            cstore: CStore {
-                // We add an empty entry for LOCAL_CRATE (which maps to zero) in
-                // order to make array indices in `metas` match with the
-                // corresponding `CrateNum`. This first entry will always remain
-                // `None`.
-                metas: IndexVec::from_elem_n(None, 1),
-                injected_panic_runtime: None,
-                allocator_kind: None,
-                alloc_error_handler_kind: None,
-                has_global_allocator: false,
-                has_alloc_error_handler: false,
-                stable_crate_ids,
-                unused_externs: Vec::new(),
-            },
-            used_extern_options: Default::default(),
+            local_crate_name,
+            cstore,
+            used_extern_options,
+            definitions,
         }
     }
-
     pub fn cstore(&self) -> &CStore {
         &self.cstore
     }
 
-    pub fn into_cstore(self) -> 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 {
@@ -989,7 +992,6 @@ pub fn postprocess(&mut self, krate: &ast::Crate) {
     pub fn process_extern_crate(
         &mut self,
         item: &ast::Item,
-        definitions: &Definitions,
         def_id: LocalDefId,
     ) -> Option<CrateNum> {
         match item.kind {
@@ -1000,7 +1002,7 @@ pub fn process_extern_crate(
                 );
                 let name = match orig_name {
                     Some(orig_name) => {
-                        validate_crate_name(self.sess, orig_name.as_str(), Some(item.span));
+                        validate_crate_name(self.sess, orig_name, Some(item.span));
                         orig_name
                     }
                     None => item.ident.name,
@@ -1013,7 +1015,7 @@ pub fn process_extern_crate(
 
                 let cnum = self.resolve_crate(name, item.span, dep_kind)?;
 
-                let path_len = definitions.def_path(def_id).data.len();
+                let path_len = self.definitions.def_path(def_id).data.len();
                 self.update_extern_crate(
                     cnum,
                     ExternCrate {
index c41ae8d55cdad6d3dcd2a9205cfd26541f62418a..7601f6bd3221efaae15ef9b76f4c54366cd9628c 100644 (file)
@@ -6,7 +6,7 @@
 use rustc_data_structures::temp_dir::MaybeTempDir;
 use rustc_hir::def_id::LOCAL_CRATE;
 use rustc_middle::ty::TyCtxt;
-use rustc_session::config::{CrateType, OutputFilenames, OutputType};
+use rustc_session::config::{CrateType, OutputType};
 use rustc_session::output::filename_for_metadata;
 use rustc_session::Session;
 use tempfile::Builder as TempFileBuilder;
@@ -38,10 +38,7 @@ pub fn emit_wrapper_file(
     out_filename
 }
 
-pub fn encode_and_write_metadata(
-    tcx: TyCtxt<'_>,
-    outputs: &OutputFilenames,
-) -> (EncodedMetadata, bool) {
+pub fn encode_and_write_metadata(tcx: TyCtxt<'_>) -> (EncodedMetadata, bool) {
     #[derive(PartialEq, Eq, PartialOrd, Ord)]
     enum MetadataKind {
         None,
@@ -64,7 +61,7 @@ enum MetadataKind {
         .unwrap_or(MetadataKind::None);
 
     let crate_name = tcx.crate_name(LOCAL_CRATE);
-    let out_filename = filename_for_metadata(tcx.sess, crate_name.as_str(), outputs);
+    let out_filename = filename_for_metadata(tcx.sess, crate_name, tcx.output_filenames(()));
     // To avoid races with another rustc process scanning the output directory,
     // we need to write the file somewhere else and atomically move it to its
     // final destination, with an `fs::rename` call. In order for the rename to
index 33cce0a411e81babf281a72e64061927c0eb1968..9d0ccfeb16898309ae374f4b6b392e032eb4d550 100644 (file)
@@ -629,6 +629,9 @@ impl CrateStore for CStore {
     fn as_any(&self) -> &dyn Any {
         self
     }
+    fn untracked_as_any(&mut self) -> &mut dyn Any {
+        self
+    }
 
     fn crate_name(&self, cnum: CrateNum) -> Symbol {
         self.get_crate_data(cnum).root.name
index 8b4c4bb2675cb62309fe840c2c5efc1303b1ca72..29f9e82da75cc58b9b6f50b2f090dde45e50d7d2 100644 (file)
@@ -1337,24 +1337,16 @@ fn encode_info_for_trait_item(&mut self, def_id: DefId) {
         debug!("EncodeContext::encode_info_for_trait_item({:?})", def_id);
         let tcx = self.tcx;
 
-        let ast_item = tcx.hir().expect_trait_item(def_id.expect_local());
-        self.tables.impl_defaultness.set(def_id.index, ast_item.defaultness);
+        let impl_defaultness = tcx.impl_defaultness(def_id.expect_local());
+        self.tables.impl_defaultness.set(def_id.index, impl_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 => {}
             ty::AssocKind::Fn => {
-                let hir::TraitItemKind::Fn(m_sig, m) = &ast_item.kind else { bug!() };
-                match *m {
-                    hir::TraitFn::Required(ref names) => {
-                        record_array!(self.tables.fn_arg_names[def_id] <- *names)
-                    }
-                    hir::TraitFn::Provided(body) => {
-                        record_array!(self.tables.fn_arg_names[def_id] <- self.tcx.hir().body_param_names(body))
-                    }
-                };
-                self.tables.asyncness.set(def_id.index, m_sig.header.asyncness);
+                record_array!(self.tables.fn_arg_names[def_id] <- tcx.fn_arg_names(def_id));
+                self.tables.asyncness.set(def_id.index, tcx.asyncness(def_id));
                 self.tables.constness.set(def_id.index, hir::Constness::NotConst);
             }
             ty::AssocKind::Type => {
index 29fe6110797e3885947169dcbdccaa83432479b7..716655c7f144d7de62e0d5c1bc64ee9a703c5b55 100644 (file)
@@ -7,7 +7,6 @@
 use rustc_serialize::opaque::FileEncoder;
 use rustc_serialize::Encoder as _;
 use rustc_span::hygiene::MacroKind;
-use std::convert::TryInto;
 use std::marker::PhantomData;
 use std::num::NonZeroUsize;
 
index e83106b1ee51507cc6807e5c4947c833136c25a7..6de68841fe91f41fa84faa97f77ce3448350d9e9 100644 (file)
@@ -1,3 +1,5 @@
+#![allow(rustc::usage_of_ty_tykind)]
+
 /// This higher-order macro declares a list of types which can be allocated by `Arena`.
 ///
 /// Specifying the `decode` modifier will add decode impls for `&T` and `&[T]` where `T` is the type
@@ -28,6 +30,7 @@ macro_rules! arena_types {
             [decode] typeck_results: rustc_middle::ty::TypeckResults<'tcx>,
             [decode] borrowck_result:
                 rustc_middle::mir::BorrowCheckResult<'tcx>,
+            [] resolver: rustc_data_structures::steal::Steal<rustc_middle::ty::ResolverAstLowering>,
             [decode] unsafety_check_result: rustc_middle::mir::UnsafetyCheckResult,
             [decode] code_region: rustc_middle::mir::coverage::CodeRegion,
             [] const_allocs: rustc_middle::mir::interpret::Allocation,
@@ -88,8 +91,8 @@ macro_rules! arena_types {
             [] hir_id_set: rustc_hir::HirIdSet,
 
             // Interned types
-            [] tys: rustc_data_structures::intern::WithStableHash<rustc_middle::ty::TyS<'tcx>>,
-            [] predicates: rustc_data_structures::intern::WithStableHash<rustc_middle::ty::PredicateS<'tcx>>,
+            [] tys: rustc_type_ir::WithCachedTypeInfo<rustc_middle::ty::TyKind<'tcx>>,
+            [] predicates: rustc_type_ir::WithCachedTypeInfo<rustc_middle::ty::PredicateKind<'tcx>>,
             [] consts: rustc_middle::ty::ConstS<'tcx>,
 
             // Note that this deliberately duplicates items in the `rustc_hir::arena`,
index 4617c17b1537ea67ee32d99430b1f3f5335e7db3..0450abed51b0652338a9bd7799d0dd2e566c62db 100644 (file)
@@ -14,7 +14,7 @@
 use rustc_middle::hir::nested_filter;
 use rustc_span::def_id::StableCrateId;
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
-use rustc_span::{Span, DUMMY_SP};
+use rustc_span::Span;
 use rustc_target::spec::abi::Abi;
 
 #[inline]
@@ -1022,7 +1022,7 @@ fn named_span(item_span: Span, ident: Ident, generics: Option<&Generics<'_>>) ->
                 ..
             }) => {
                 // Ensure that the returned span has the item's SyntaxContext.
-                fn_decl_span.find_ancestor_in_same_ctxt(*span).unwrap_or(*span)
+                fn_decl_span.find_ancestor_inside(*span).unwrap_or(*span)
             }
             _ => self.span_with_body(hir_id),
         };
@@ -1162,7 +1162,7 @@ pub(super) fn crate_hash(tcx: TyCtxt<'_>, crate_num: CrateNum) -> Svh {
                 .filter_map(|(def_id, info)| {
                     let _ = info.as_owner()?;
                     let def_path_hash = definitions.def_path_hash(def_id);
-                    let span = resolutions.source_span.get(def_id).unwrap_or(&DUMMY_SP);
+                    let span = tcx.source_span(def_id);
                     debug_assert_eq!(span.parent(), None);
                     Some((def_path_hash, span))
                 })
index 02fd03c02839a69f7eb6e847d14248ebc06470c4..3f6e29ad611c911daf807d72be51dc5eb6e00780 100644 (file)
@@ -141,8 +141,6 @@ pub fn provide(providers: &mut Providers) {
     providers.hir_attrs = |tcx, id| {
         tcx.hir_crate(()).owners[id.def_id].as_owner().map_or(AttributeMap::EMPTY, |o| &o.attrs)
     };
-    providers.source_span =
-        |tcx, def_id| tcx.resolutions(()).source_span.get(def_id).copied().unwrap_or(DUMMY_SP);
     providers.def_span = |tcx, def_id| {
         let def_id = def_id.expect_local();
         let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
index 45d33a1659ffa42fbc0ae603025f44c80bdbda4a..bea884c856a95bd616b229e20f9f2984154ab573 100644 (file)
@@ -26,8 +26,10 @@ pub struct CodegenFnAttrs {
     /// The `#[target_feature(enable = "...")]` attribute and the enabled
     /// features (only enabled features are supported right now).
     pub target_features: Vec<Symbol>,
-    /// The `#[linkage = "..."]` attribute and the value we found.
+    /// The `#[linkage = "..."]` attribute on Rust-defined items and the value we found.
     pub linkage: Option<Linkage>,
+    /// The `#[linkage = "..."]` attribute on foreign items and the value we found.
+    pub import_linkage: Option<Linkage>,
     /// The `#[link_section = "..."]` attribute, or what executable section this
     /// should be placed in.
     pub link_section: Option<Symbol>,
@@ -113,6 +115,7 @@ pub const fn new() -> CodegenFnAttrs {
             link_ordinal: None,
             target_features: vec![],
             linkage: None,
+            import_linkage: None,
             link_section: None,
             no_sanitize: SanitizerSet::empty(),
             instruction_set: None,
index efa9464529e71ca14473852c3b6abb4cffdb04db..0b55757eb038298d32ee3598e9a07fe5732e0d15 100644 (file)
@@ -3,7 +3,6 @@
 use rustc_macros::HashStable;
 use rustc_span::Symbol;
 
-use std::cmp::Ord;
 use std::fmt::{self, Debug, Formatter};
 
 rustc_index::newtype_index! {
index 5f911d5884a3353019f39ee10521beaab33bdcd1..221105ac48f79b5487374c7969cdd058d1515755 100644 (file)
@@ -103,7 +103,7 @@ fn hash<H: hash::Hasher>(&self, state: &mut H) {
 /// Interned types generally have an `Outer` type and an `Inner` type, where
 /// `Outer` is a newtype around `Interned<Inner>`, and all the operations are
 /// done on `Outer`, because all occurrences are interned. E.g. `Ty` is an
-/// outer type and `TyS` is its inner type.
+/// outer type and `TyKind` is its inner type.
 ///
 /// Here things are different because only const allocations are interned. This
 /// means that both the inner type (`Allocation`) and the outer type
index d79cd8b7a8a4b075c4bfdcc30a5379141d6bc385..8fe349d9640dafd776814d0feb5f9b8175a7e92f 100644 (file)
@@ -95,7 +95,6 @@ macro_rules! throw_machine_stop {
 mod queries;
 mod value;
 
-use std::convert::TryFrom;
 use std::fmt;
 use std::io;
 use std::io::{Read, Write};
index 9c270ba1ec179939e18834ca0f773c9efbea4836..b0830991076206930b030985cdab10732d551744 100644 (file)
@@ -3,7 +3,6 @@
 use rustc_macros::HashStable;
 use rustc_target::abi::{HasDataLayout, Size};
 
-use std::convert::{TryFrom, TryInto};
 use std::fmt;
 
 ////////////////////////////////////////////////////////////////////////////////
index e6636e50e6e7ab0a1acf50e90cf57ed963c70c6a..88fb14eb359424e468ac55f953092fbc18cae2ee 100644 (file)
@@ -1,4 +1,3 @@
-use std::convert::{TryFrom, TryInto};
 use std::fmt;
 
 use either::{Either, Left, Right};
index 20dde64e51b0118e52e0927fa631e0e989d50629..db4fe6f886b2549044777dd6f0e7b399fc0c3bfc 100644 (file)
@@ -36,7 +36,6 @@
 use either::Either;
 
 use std::borrow::Cow;
-use std::convert::TryInto;
 use std::fmt::{self, Debug, Display, Formatter, Write};
 use std::ops::{ControlFlow, Index, IndexMut};
 use std::{iter, mem};
@@ -100,13 +99,9 @@ fn local_decls(&self) -> &LocalDecls<'tcx> {
 /// pass will be named after the type, and it will consist of a main
 /// loop that goes over each available MIR and applies `run_pass`.
 pub trait MirPass<'tcx> {
-    fn name(&self) -> Cow<'_, str> {
+    fn name(&self) -> &str {
         let name = std::any::type_name::<Self>();
-        if let Some(tail) = name.rfind(':') {
-            Cow::from(&name[tail + 1..])
-        } else {
-            Cow::from(name)
-        }
+        if let Some((_, tail)) = name.rsplit_once(':') { tail } else { name }
     }
 
     /// Returns `true` if this pass is enabled with the current combination of compiler flags.
@@ -182,35 +177,6 @@ pub fn parse(phase: Option<String>) -> Self {
     }
 }
 
-impl Display for MirPhase {
-    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
-        match self {
-            MirPhase::Built => write!(f, "built"),
-            MirPhase::Analysis(p) => write!(f, "analysis-{}", p),
-            MirPhase::Runtime(p) => write!(f, "runtime-{}", p),
-        }
-    }
-}
-
-impl Display for AnalysisPhase {
-    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
-        match self {
-            AnalysisPhase::Initial => write!(f, "initial"),
-            AnalysisPhase::PostCleanup => write!(f, "post_cleanup"),
-        }
-    }
-}
-
-impl Display for RuntimePhase {
-    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
-        match self {
-            RuntimePhase::Initial => write!(f, "initial"),
-            RuntimePhase::PostCleanup => write!(f, "post_cleanup"),
-            RuntimePhase::Optimized => write!(f, "optimized"),
-        }
-    }
-}
-
 /// Where a specific `mir::Body` comes from.
 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
 #[derive(HashStable, TyEncodable, TyDecodable, TypeFoldable, TypeVisitable)]
@@ -368,7 +334,7 @@ pub fn new(
 
         let mut body = Body {
             phase: MirPhase::Built,
-            pass_count: 1,
+            pass_count: 0,
             source,
             basic_blocks: BasicBlocks::new(basic_blocks),
             source_scopes,
@@ -403,7 +369,7 @@ pub fn new(
     pub fn new_cfg_only(basic_blocks: IndexVec<BasicBlock, BasicBlockData<'tcx>>) -> Self {
         let mut body = Body {
             phase: MirPhase::Built,
-            pass_count: 1,
+            pass_count: 0,
             source: MirSource::item(CRATE_DEF_ID.to_def_id()),
             basic_blocks: BasicBlocks::new(basic_blocks),
             source_scopes: IndexVec::new(),
index 1cac656674d697a407dcb858cfe7967338c533e1..2a4ff4b8810dbc513171e07fb969e8f299e033f3 100644 (file)
@@ -16,7 +16,6 @@
     Pointer, Provenance,
 };
 use rustc_middle::mir::visit::Visitor;
-use rustc_middle::mir::MirSource;
 use rustc_middle::mir::*;
 use rustc_middle::ty::{self, TyCtxt};
 use rustc_target::abi::Size;
@@ -74,7 +73,7 @@ pub enum PassWhere {
 #[inline]
 pub fn dump_mir<'tcx, F>(
     tcx: TyCtxt<'tcx>,
-    pass_num: Option<&dyn Display>,
+    pass_num: bool,
     pass_name: &str,
     disambiguator: &dyn Display,
     body: &Body<'tcx>,
@@ -111,7 +110,7 @@ pub fn dump_enabled<'tcx>(tcx: TyCtxt<'tcx>, pass_name: &str, def_id: DefId) ->
 
 fn dump_matched_mir_node<'tcx, F>(
     tcx: TyCtxt<'tcx>,
-    pass_num: Option<&dyn Display>,
+    pass_num: bool,
     pass_name: &str,
     disambiguator: &dyn Display,
     body: &Body<'tcx>,
@@ -120,8 +119,7 @@ fn dump_matched_mir_node<'tcx, F>(
     F: FnMut(PassWhere, &mut dyn Write) -> io::Result<()>,
 {
     let _: io::Result<()> = try {
-        let mut file =
-            create_dump_file(tcx, "mir", pass_num, pass_name, disambiguator, body.source)?;
+        let mut file = create_dump_file(tcx, "mir", pass_num, pass_name, disambiguator, body)?;
         // see notes on #41697 above
         let def_path =
             ty::print::with_forced_impl_filename_line!(tcx.def_path_str(body.source.def_id()));
@@ -143,16 +141,14 @@ fn dump_matched_mir_node<'tcx, F>(
 
     if tcx.sess.opts.unstable_opts.dump_mir_graphviz {
         let _: io::Result<()> = try {
-            let mut file =
-                create_dump_file(tcx, "dot", pass_num, pass_name, disambiguator, body.source)?;
+            let mut file = create_dump_file(tcx, "dot", pass_num, pass_name, disambiguator, body)?;
             write_mir_fn_graphviz(tcx, body, false, &mut file)?;
         };
     }
 
     if let Some(spanview) = tcx.sess.opts.unstable_opts.dump_mir_spanview {
         let _: io::Result<()> = try {
-            let file_basename =
-                dump_file_basename(tcx, pass_num, pass_name, disambiguator, body.source);
+            let file_basename = dump_file_basename(tcx, pass_num, pass_name, disambiguator, body);
             let mut file = create_dump_file_with_basename(tcx, &file_basename, "html")?;
             if body.source.def_id().is_local() {
                 write_mir_fn_spanview(tcx, body, spanview, &file_basename, &mut file)?;
@@ -165,11 +161,12 @@ fn dump_matched_mir_node<'tcx, F>(
 /// where we should dump a MIR representation output files.
 fn dump_file_basename<'tcx>(
     tcx: TyCtxt<'tcx>,
-    pass_num: Option<&dyn Display>,
+    pass_num: bool,
     pass_name: &str,
     disambiguator: &dyn Display,
-    source: MirSource<'tcx>,
+    body: &Body<'tcx>,
 ) -> String {
+    let source = body.source;
     let promotion_id = match source.promoted {
         Some(id) => format!("-{:?}", id),
         None => String::new(),
@@ -178,9 +175,10 @@ fn dump_file_basename<'tcx>(
     let pass_num = if tcx.sess.opts.unstable_opts.dump_mir_exclude_pass_number {
         String::new()
     } else {
-        match pass_num {
-            None => ".-------".to_string(),
-            Some(pass_num) => format!(".{}", pass_num),
+        if pass_num {
+            format!(".{:03}-{:03}", body.phase.phase_index(), body.pass_count)
+        } else {
+            ".-------".to_string()
         }
     };
 
@@ -250,14 +248,14 @@ fn create_dump_file_with_basename(
 pub fn create_dump_file<'tcx>(
     tcx: TyCtxt<'tcx>,
     extension: &str,
-    pass_num: Option<&dyn Display>,
+    pass_num: bool,
     pass_name: &str,
     disambiguator: &dyn Display,
-    source: MirSource<'tcx>,
+    body: &Body<'tcx>,
 ) -> io::Result<io::BufWriter<fs::File>> {
     create_dump_file_with_basename(
         tcx,
-        &dump_file_basename(tcx, pass_num, pass_name, disambiguator, source),
+        &dump_file_basename(tcx, pass_num, pass_name, disambiguator, body),
         extension,
     )
 }
index f2030b91b9b65e679cfe1b12d16b5d888c00381b..99e59c770d754152140eaf8b6558fc370b6344dc 100644 (file)
@@ -6,6 +6,7 @@
 use super::{BasicBlock, Constant, Field, Local, SwitchTargets, UserTypeProjection};
 
 use crate::mir::coverage::{CodeRegion, CoverageKind};
+use crate::traits::Reveal;
 use crate::ty::adjustment::PointerCast;
 use crate::ty::subst::SubstsRef;
 use crate::ty::{self, List, Ty};
@@ -89,6 +90,26 @@ pub enum MirPhase {
     Runtime(RuntimePhase),
 }
 
+impl MirPhase {
+    pub fn name(&self) -> &'static str {
+        match *self {
+            MirPhase::Built => "built",
+            MirPhase::Analysis(AnalysisPhase::Initial) => "analysis",
+            MirPhase::Analysis(AnalysisPhase::PostCleanup) => "analysis-post-cleanup",
+            MirPhase::Runtime(RuntimePhase::Initial) => "runtime",
+            MirPhase::Runtime(RuntimePhase::PostCleanup) => "runtime-post-cleanup",
+            MirPhase::Runtime(RuntimePhase::Optimized) => "runtime-optimized",
+        }
+    }
+
+    pub fn reveal(&self) -> Reveal {
+        match *self {
+            MirPhase::Built | MirPhase::Analysis(_) => Reveal::UserFacing,
+            MirPhase::Runtime(_) => Reveal::All,
+        }
+    }
+}
+
 /// See [`MirPhase::Analysis`].
 #[derive(Copy, Clone, TyEncodable, TyDecodable, Debug, PartialEq, Eq, PartialOrd, Ord)]
 #[derive(HashStable)]
@@ -387,7 +408,7 @@ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 #[derive(Copy, Clone, TyEncodable, TyDecodable, Debug, PartialEq, Eq, Hash, HashStable)]
 #[rustc_pass_by_value]
 pub enum RetagKind {
-    /// The initial retag when entering a function.
+    /// The initial retag of arguments when entering a function.
     FnEntry,
     /// Retag preparing for a two-phase borrow.
     TwoPhase,
@@ -505,12 +526,6 @@ pub enum TerminatorKind<'tcx> {
     SwitchInt {
         /// The discriminant value being tested.
         discr: Operand<'tcx>,
-
-        /// The type of value being tested.
-        /// This is always the same as the type of `discr`.
-        /// FIXME: remove this redundant information. Currently, it is relied on by pretty-printing.
-        switch_ty: Ty<'tcx>,
-
         targets: SwitchTargets,
     },
 
index 4ea333cff7d9db9841502b4a18362a36148dc3b0..013a1bccd3bd1fd85af72a5a31db156e4e0c3416 100644 (file)
@@ -1,6 +1,3 @@
-use crate::mir;
-use crate::mir::interpret::Scalar;
-use crate::ty::{self, Ty, TyCtxt};
 use smallvec::{smallvec, SmallVec};
 
 use super::{BasicBlock, InlineAsmOperand, Operand, SourceInfo, TerminatorKind};
@@ -131,17 +128,8 @@ pub fn unwind_mut(&mut self) -> Option<&mut Option<BasicBlock>> {
 }
 
 impl<'tcx> TerminatorKind<'tcx> {
-    pub fn if_(
-        tcx: TyCtxt<'tcx>,
-        cond: Operand<'tcx>,
-        t: BasicBlock,
-        f: BasicBlock,
-    ) -> TerminatorKind<'tcx> {
-        TerminatorKind::SwitchInt {
-            discr: cond,
-            switch_ty: tcx.types.bool,
-            targets: SwitchTargets::static_if(0, f, t),
-        }
+    pub fn if_(cond: Operand<'tcx>, t: BasicBlock, f: BasicBlock) -> TerminatorKind<'tcx> {
+        TerminatorKind::SwitchInt { discr: cond, targets: SwitchTargets::static_if(0, f, t) }
     }
 
     pub fn successors(&self) -> Successors<'_> {
@@ -264,11 +252,9 @@ pub fn unwind_mut(&mut self) -> Option<&mut Option<BasicBlock>> {
         }
     }
 
-    pub fn as_switch(&self) -> Option<(&Operand<'tcx>, Ty<'tcx>, &SwitchTargets)> {
+    pub fn as_switch(&self) -> Option<(&Operand<'tcx>, &SwitchTargets)> {
         match self {
-            TerminatorKind::SwitchInt { discr, switch_ty, targets } => {
-                Some((discr, *switch_ty, targets))
-            }
+            TerminatorKind::SwitchInt { discr, targets } => Some((discr, targets)),
             _ => None,
         }
     }
@@ -403,21 +389,12 @@ pub fn fmt_successor_labels(&self) -> Vec<Cow<'static, str>> {
         match *self {
             Return | Resume | Abort | Unreachable | GeneratorDrop => vec![],
             Goto { .. } => vec!["".into()],
-            SwitchInt { ref targets, switch_ty, .. } => ty::tls::with(|tcx| {
-                let param_env = ty::ParamEnv::empty();
-                let switch_ty = tcx.lift(switch_ty).unwrap();
-                let size = tcx.layout_of(param_env.and(switch_ty)).unwrap().size;
-                targets
-                    .values
-                    .iter()
-                    .map(|&u| {
-                        mir::ConstantKind::from_scalar(tcx, Scalar::from_uint(u, size), switch_ty)
-                            .to_string()
-                            .into()
-                    })
-                    .chain(iter::once("otherwise".into()))
-                    .collect()
-            }),
+            SwitchInt { ref targets, .. } => targets
+                .values
+                .iter()
+                .map(|&u| Cow::Owned(u.to_string()))
+                .chain(iter::once("otherwise".into()))
+                .collect(),
             Call { target: Some(_), cleanup: Some(_), .. } => {
                 vec!["return".into(), "unwind".into()]
             }
index b21f50ae5eaa95a42689ce9ccbf614c65aced654..2ee3f551529f986c44525f9857994b4a29cbafba 100644 (file)
@@ -477,11 +477,9 @@ fn super_terminator(&mut self,
 
                     TerminatorKind::SwitchInt {
                         discr,
-                        switch_ty,
                         targets: _
                     } => {
                         self.visit_operand(discr, location);
-                        self.visit_ty($(& $mutability)? *switch_ty, TyContext::Location(location));
                     }
 
                     TerminatorKind::Drop {
index e1220320eea1b5732808dea43d0644f1e48565e9..ab512804330b9f647ca9bc14edf2e0d698b53b4a 100644 (file)
@@ -33,7 +33,7 @@
     }
 
     query resolver_for_lowering(_: ()) -> &'tcx Steal<ty::ResolverAstLowering> {
-        eval_always
+        feedable
         no_hash
         desc { "getting the resolver for lowering" }
     }
@@ -43,6 +43,8 @@
     /// This span is meant for dep-tracking rather than diagnostics. It should not be used outside
     /// of rustc_middle::hir::source_map.
     query source_span(key: LocalDefId) -> Span {
+        // Accesses untracked data
+        eval_always
         desc { "getting the source span" }
     }
 
         desc { |tcx| "looking up span for `{}`", tcx.def_path_str(def_id) }
         cache_on_disk_if { def_id.is_local() }
         separate_provide_extern
+        feedable
     }
 
     /// Gets the span for the identifier of the definition.
index fb152b63f63448675059b251cbd6191681df48fa..d40d7de5f315fc3a18194348caf84fe05baeb8c4 100644 (file)
@@ -12,7 +12,6 @@
 use crate::ty::{self, Ty, TyCtxt};
 use rustc_hir::def_id::DefId;
 use rustc_span::source_map::Span;
-use std::iter::FromIterator;
 
 pub mod type_op {
     use crate::ty::fold::TypeFoldable;
index f3186e1c30c3dc4b4229f8501ac5e91d33131edd..2a8a4d598882d0c0cd1b83abed69dd574fdc866d 100644 (file)
@@ -2,7 +2,6 @@
 use rustc_apfloat::Float;
 use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
 use rustc_target::abi::Size;
-use std::convert::{TryFrom, TryInto};
 use std::fmt;
 use std::num::NonZeroU8;
 
index becc2b805dd1ee9ffb3ca9c50eb6b346e697a996..d9721863a58c801fa49c21594cfc26309a2dc47d 100644 (file)
@@ -1,5 +1,3 @@
-use std::convert::TryInto;
-
 use super::Const;
 use crate::mir;
 use crate::mir::interpret::{AllocId, ConstValue, Scalar};
index a9a7a2c8b01cced710a674156f94c20ce246a95f..7d4971d1e9e62d6fb5166ed9a5e248ea44164d2d 100644 (file)
@@ -1,5 +1,7 @@
 //! Type context book-keeping.
 
+#![allow(rustc::usage_of_ty_tykind)]
+
 use crate::arena::Arena;
 use crate::dep_graph::{DepGraph, DepKindStruct};
 use crate::hir::place::Place as HirPlace;
     self, AdtDef, AdtDefData, AdtKind, Binder, BindingMode, BoundVar, CanonicalPolyFnSig,
     ClosureSizeProfileData, Const, ConstS, DefIdTree, FloatTy, FloatVar, FloatVid,
     GenericParamDefKind, InferTy, IntTy, IntVar, IntVid, List, ParamConst, ParamTy,
-    PolyExistentialPredicate, PolyFnSig, Predicate, PredicateKind, PredicateS, ProjectionTy,
-    Region, RegionKind, ReprOptions, TraitObjectVisitor, Ty, TyKind, TyS, TyVar, TyVid, TypeAndMut,
-    UintTy, Visibility,
+    PolyExistentialPredicate, PolyFnSig, Predicate, PredicateKind, ProjectionTy, Region,
+    RegionKind, ReprOptions, TraitObjectVisitor, Ty, TyKind, TyVar, TyVid, TypeAndMut, UintTy,
+    Visibility,
 };
 use crate::ty::{GenericArg, GenericArgKind, InternalSubsts, SubstsRef, UserSubsts};
 use rustc_ast as ast;
 use rustc_data_structures::fingerprint::Fingerprint;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
-use rustc_data_structures::intern::{Interned, WithStableHash};
+use rustc_data_structures::intern::Interned;
 use rustc_data_structures::memmap::Mmap;
 use rustc_data_structures::profiling::SelfProfilerRef;
 use rustc_data_structures::sharded::{IntoPointer, ShardedHashMap};
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 use rustc_data_structures::steal::Steal;
-use rustc_data_structures::sync::{self, Lock, Lrc, ReadGuard, RwLock, WorkerLocal};
+use rustc_data_structures::sync::{self, Lock, Lrc, ReadGuard, WorkerLocal};
 use rustc_data_structures::unord::UnordSet;
 use rustc_data_structures::vec_map::VecMap;
 use rustc_errors::{
@@ -57,7 +59,7 @@
 use rustc_query_system::ich::StableHashingContext;
 use rustc_serialize::opaque::{FileEncodeResult, FileEncoder};
 use rustc_session::config::{CrateType, OutputFilenames};
-use rustc_session::cstore::CrateStoreDyn;
+use rustc_session::cstore::{CrateStoreDyn, Untracked};
 use rustc_session::lint::Lint;
 use rustc_session::Limit;
 use rustc_session::Session;
@@ -68,6 +70,7 @@
 use rustc_target::abi::{Layout, LayoutS, TargetDataLayout, VariantIdx};
 use rustc_target::spec::abi;
 use rustc_type_ir::sty::TyKind::*;
+use rustc_type_ir::WithCachedTypeInfo;
 use rustc_type_ir::{DynKind, InternAs, InternIteratorElement, Interner, TypeFlags};
 
 use std::any::Any;
@@ -81,7 +84,7 @@
 use std::ops::{Bound, Deref};
 use std::sync::Arc;
 
-use super::{ImplPolarity, ResolverOutputs, RvalueScopes};
+use super::{ImplPolarity, RvalueScopes};
 
 pub trait OnDiskCache<'tcx>: rustc_data_structures::sync::Sync {
     /// Creates a new `OnDiskCache` instance from the serialized data in `data`.
@@ -137,13 +140,13 @@ pub struct CtxtInterners<'tcx> {
 
     // Specifically use a speedy hash algorithm for these hash sets, since
     // they're accessed quite often.
-    type_: InternedSet<'tcx, WithStableHash<TyS<'tcx>>>,
+    type_: InternedSet<'tcx, WithCachedTypeInfo<TyKind<'tcx>>>,
     const_lists: InternedSet<'tcx, List<ty::Const<'tcx>>>,
     substs: InternedSet<'tcx, InternalSubsts<'tcx>>,
     canonical_var_infos: InternedSet<'tcx, List<CanonicalVarInfo<'tcx>>>,
     region: InternedSet<'tcx, RegionKind<'tcx>>,
     poly_existential_predicates: InternedSet<'tcx, List<PolyExistentialPredicate<'tcx>>>,
-    predicate: InternedSet<'tcx, WithStableHash<PredicateS<'tcx>>>,
+    predicate: InternedSet<'tcx, WithCachedTypeInfo<ty::Binder<'tcx, PredicateKind<'tcx>>>>,
     predicates: InternedSet<'tcx, List<Predicate<'tcx>>>,
     projs: InternedSet<'tcx, List<ProjectionKind>>,
     place_elems: InternedSet<'tcx, List<PlaceElem<'tcx>>>,
@@ -179,30 +182,19 @@ fn new(arena: &'tcx WorkerLocal<Arena<'tcx>>) -> CtxtInterners<'tcx> {
     /// Interns a type.
     #[allow(rustc::usage_of_ty_tykind)]
     #[inline(never)]
-    fn intern_ty(
-        &self,
-        kind: TyKind<'tcx>,
-        sess: &Session,
-        definitions: &rustc_hir::definitions::Definitions,
-        cstore: &CrateStoreDyn,
-        source_span: &IndexVec<LocalDefId, Span>,
-    ) -> Ty<'tcx> {
+    fn intern_ty(&self, kind: TyKind<'tcx>, sess: &Session, untracked: &Untracked) -> Ty<'tcx> {
         Ty(Interned::new_unchecked(
             self.type_
                 .intern(kind, |kind| {
                     let flags = super::flags::FlagComputation::for_kind(&kind);
-                    let stable_hash =
-                        self.stable_hash(&flags, sess, definitions, cstore, source_span, &kind);
+                    let stable_hash = self.stable_hash(&flags, sess, untracked, &kind);
 
-                    let ty_struct = TyS {
-                        kind,
+                    InternedInSet(self.arena.alloc(WithCachedTypeInfo {
+                        internee: kind,
+                        stable_hash,
                         flags: flags.flags,
                         outer_exclusive_binder: flags.outer_exclusive_binder,
-                    };
-
-                    InternedInSet(
-                        self.arena.alloc(WithStableHash { internee: ty_struct, stable_hash }),
-                    )
+                    }))
                 })
                 .0,
         ))
@@ -212,9 +204,7 @@ fn stable_hash<'a, T: HashStable<StableHashingContext<'a>>>(
         &self,
         flags: &ty::flags::FlagComputation,
         sess: &'a Session,
-        definitions: &'a rustc_hir::definitions::Definitions,
-        cstore: &'a CrateStoreDyn,
-        source_span: &'a IndexVec<LocalDefId, Span>,
+        untracked: &'a Untracked,
         val: &T,
     ) -> Fingerprint {
         // It's impossible to hash inference variables (and will ICE), so we don't need to try to cache them.
@@ -223,7 +213,7 @@ fn stable_hash<'a, T: HashStable<StableHashingContext<'a>>>(
             Fingerprint::ZERO
         } else {
             let mut hasher = StableHasher::new();
-            let mut hcx = StableHashingContext::new(sess, definitions, cstore, source_span);
+            let mut hcx = StableHashingContext::new(sess, untracked);
             val.hash_stable(&mut hcx, &mut hasher);
             hasher.finish()
         }
@@ -234,28 +224,21 @@ fn intern_predicate(
         &self,
         kind: Binder<'tcx, PredicateKind<'tcx>>,
         sess: &Session,
-        definitions: &rustc_hir::definitions::Definitions,
-        cstore: &CrateStoreDyn,
-        source_span: &IndexVec<LocalDefId, Span>,
+        untracked: &Untracked,
     ) -> Predicate<'tcx> {
         Predicate(Interned::new_unchecked(
             self.predicate
                 .intern(kind, |kind| {
                     let flags = super::flags::FlagComputation::for_predicate(kind);
 
-                    let stable_hash =
-                        self.stable_hash(&flags, sess, definitions, cstore, source_span, &kind);
+                    let stable_hash = self.stable_hash(&flags, sess, untracked, &kind);
 
-                    let predicate_struct = PredicateS {
-                        kind,
+                    InternedInSet(self.arena.alloc(WithCachedTypeInfo {
+                        internee: kind,
+                        stable_hash,
                         flags: flags.flags,
                         outer_exclusive_binder: flags.outer_exclusive_binder,
-                    };
-
-                    InternedInSet(
-                        self.arena
-                            .alloc(WithStableHash { internee: predicate_struct, stable_hash }),
-                    )
+                    }))
                 })
                 .0,
         ))
@@ -671,6 +654,14 @@ pub fn field_indices_mut(&mut self) -> LocalTableInContextMut<'_, usize> {
         LocalTableInContextMut { hir_owner: self.hir_owner, data: &mut self.field_indices }
     }
 
+    pub fn field_index(&self, id: hir::HirId) -> usize {
+        self.field_indices().get(id).cloned().expect("no index for a field")
+    }
+
+    pub fn opt_field_index(&self, id: hir::HirId) -> Option<usize> {
+        self.field_indices().get(id).cloned()
+    }
+
     pub fn user_provided_types(&self) -> LocalTableInContext<'_, CanonicalUserType<'tcx>> {
         LocalTableInContext { hir_owner: self.hir_owner, data: &self.user_provided_types }
     }
@@ -958,11 +949,9 @@ impl<'tcx> CommonTypes<'tcx> {
     fn new(
         interners: &CtxtInterners<'tcx>,
         sess: &Session,
-        definitions: &rustc_hir::definitions::Definitions,
-        cstore: &CrateStoreDyn,
-        source_span: &IndexVec<LocalDefId, Span>,
+        untracked: &Untracked,
     ) -> CommonTypes<'tcx> {
-        let mk = |ty| interners.intern_ty(ty, sess, definitions, cstore, source_span);
+        let mk = |ty| interners.intern_ty(ty, sess, untracked);
 
         CommonTypes {
             unit: mk(Tuple(List::empty())),
@@ -1034,16 +1023,29 @@ pub struct FreeRegionInfo {
 
 /// This struct should only be created by `create_def`.
 #[derive(Copy, Clone)]
-pub struct TyCtxtFeed<'tcx> {
+pub struct TyCtxtFeed<'tcx, KEY: Copy> {
     pub tcx: TyCtxt<'tcx>,
     // Do not allow direct access, as downstream code must not mutate this field.
-    def_id: LocalDefId,
+    key: KEY,
+}
+
+impl<'tcx> TyCtxt<'tcx> {
+    pub fn feed_unit_query(self) -> TyCtxtFeed<'tcx, ()> {
+        TyCtxtFeed { tcx: self, key: () }
+    }
 }
 
-impl<'tcx> TyCtxtFeed<'tcx> {
+impl<'tcx, KEY: Copy> TyCtxtFeed<'tcx, KEY> {
+    #[inline(always)]
+    pub fn key(&self) -> KEY {
+        self.key
+    }
+}
+
+impl<'tcx> TyCtxtFeed<'tcx, LocalDefId> {
     #[inline(always)]
     pub fn def_id(&self) -> LocalDefId {
-        self.def_id
+        self.key
     }
 }
 
@@ -1095,11 +1097,9 @@ pub struct GlobalCtxt<'tcx> {
     /// Common consts, pre-interned for your convenience.
     pub consts: CommonConsts<'tcx>,
 
-    definitions: RwLock<Definitions>,
-
+    untracked: Untracked,
     /// Output of the resolver.
     pub(crate) untracked_resolutions: ty::ResolverGlobalCtxt,
-    untracked_resolver_for_lowering: Steal<ty::ResolverAstLowering>,
     /// The entire crate as AST. This field serves as the input for the hir_crate query,
     /// which lowers it from AST to HIR. It must not be read or used by anything else.
     pub untracked_crate: Steal<Lrc<ast::Crate>>,
@@ -1262,32 +1262,21 @@ pub fn create_global_ctxt(
         lint_store: Lrc<dyn Any + sync::Send + sync::Sync>,
         arena: &'tcx WorkerLocal<Arena<'tcx>>,
         hir_arena: &'tcx WorkerLocal<hir::Arena<'tcx>>,
-        resolver_outputs: ResolverOutputs,
+        untracked_resolutions: ty::ResolverGlobalCtxt,
+        untracked: Untracked,
         krate: Lrc<ast::Crate>,
         dep_graph: DepGraph,
         on_disk_cache: Option<&'tcx dyn OnDiskCache<'tcx>>,
         queries: &'tcx dyn query::QueryEngine<'tcx>,
         query_kinds: &'tcx [DepKindStruct<'tcx>],
-        crate_name: &str,
+        crate_name: Symbol,
         output_filenames: OutputFilenames,
     ) -> GlobalCtxt<'tcx> {
-        let ResolverOutputs {
-            definitions,
-            global_ctxt: untracked_resolutions,
-            ast_lowering: untracked_resolver_for_lowering,
-        } = resolver_outputs;
         let data_layout = s.target.parse_data_layout().unwrap_or_else(|err| {
             s.emit_fatal(err);
         });
         let interners = CtxtInterners::new(arena);
-        let common_types = CommonTypes::new(
-            &interners,
-            s,
-            &definitions,
-            &*untracked_resolutions.cstore,
-            // This is only used to create a stable hashing context.
-            &untracked_resolutions.source_span,
-        );
+        let common_types = CommonTypes::new(&interners, s, &untracked);
         let common_lifetimes = CommonLifetimes::new(&interners);
         let common_consts = CommonConsts::new(&interners, &common_types);
 
@@ -1298,13 +1287,12 @@ pub fn create_global_ctxt(
             hir_arena,
             interners,
             dep_graph,
-            definitions: RwLock::new(definitions),
             prof: s.prof.clone(),
             types: common_types,
             lifetimes: common_lifetimes,
             consts: common_consts,
+            untracked,
             untracked_resolutions,
-            untracked_resolver_for_lowering: Steal::new(untracked_resolver_for_lowering),
             untracked_crate: Steal::new(krate),
             on_disk_cache,
             queries,
@@ -1314,7 +1302,7 @@ pub fn create_global_ctxt(
             pred_rcache: Default::default(),
             selection_cache: Default::default(),
             evaluation_cache: Default::default(),
-            crate_name: Symbol::intern(crate_name),
+            crate_name,
             data_layout,
             alloc_map: Lock::new(interpret::AllocMap::new()),
             output_filenames: Arc::new(output_filenames),
@@ -1417,7 +1405,7 @@ pub fn def_key(self, id: DefId) -> rustc_hir::definitions::DefKey {
         if let Some(id) = id.as_local() {
             self.definitions_untracked().def_key(id)
         } else {
-            self.untracked_resolutions.cstore.def_key(id)
+            self.untracked.cstore.def_key(id)
         }
     }
 
@@ -1431,7 +1419,7 @@ pub fn def_path(self, id: DefId) -> rustc_hir::definitions::DefPath {
         if let Some(id) = id.as_local() {
             self.definitions_untracked().def_path(id)
         } else {
-            self.untracked_resolutions.cstore.def_path(id)
+            self.untracked.cstore.def_path(id)
         }
     }
 
@@ -1441,7 +1429,7 @@ pub fn def_path_hash(self, def_id: DefId) -> rustc_hir::definitions::DefPathHash
         if let Some(def_id) = def_id.as_local() {
             self.definitions_untracked().def_path_hash(def_id)
         } else {
-            self.untracked_resolutions.cstore.def_path_hash(def_id)
+            self.untracked.cstore.def_path_hash(def_id)
         }
     }
 
@@ -1450,7 +1438,7 @@ pub fn stable_crate_id(self, crate_num: CrateNum) -> StableCrateId {
         if crate_num == LOCAL_CRATE {
             self.sess.local_stable_crate_id()
         } else {
-            self.untracked_resolutions.cstore.stable_crate_id(crate_num)
+            self.untracked.cstore.stable_crate_id(crate_num)
         }
     }
 
@@ -1461,7 +1449,7 @@ pub fn stable_crate_id_to_crate_num(self, stable_crate_id: StableCrateId) -> Cra
         if stable_crate_id == self.sess.local_stable_crate_id() {
             LOCAL_CRATE
         } else {
-            self.untracked_resolutions.cstore.stable_crate_id_to_crate_num(stable_crate_id)
+            self.untracked.cstore.stable_crate_id_to_crate_num(stable_crate_id)
         }
     }
 
@@ -1476,11 +1464,11 @@ pub fn def_path_hash_to_def_id(self, hash: DefPathHash, err: &mut dyn FnMut() ->
         // If this is a DefPathHash from the local crate, we can look up the
         // DefId in the tcx's `Definitions`.
         if stable_crate_id == self.sess.local_stable_crate_id() {
-            self.definitions.read().local_def_path_hash_to_def_id(hash, err).to_def_id()
+            self.untracked.definitions.read().local_def_path_hash_to_def_id(hash, err).to_def_id()
         } else {
             // If this is a DefPathHash from an upstream crate, let the CrateStore map
             // it to a DefId.
-            let cstore = &*self.untracked_resolutions.cstore;
+            let cstore = &*self.untracked.cstore;
             let cnum = cstore.stable_crate_id_to_crate_num(stable_crate_id);
             cstore.def_path_hash_to_def_id(cnum, hash)
         }
@@ -1494,7 +1482,7 @@ pub fn def_path_debug_str(self, def_id: DefId) -> String {
         let (crate_name, stable_crate_id) = if def_id.is_local() {
             (self.crate_name, self.sess.local_stable_crate_id())
         } else {
-            let cstore = &*self.untracked_resolutions.cstore;
+            let cstore = &*self.untracked.cstore;
             (cstore.crate_name(def_id.krate), cstore.stable_crate_id(def_id.krate))
         };
 
@@ -1507,13 +1495,15 @@ pub fn def_path_debug_str(self, def_id: DefId) -> String {
             self.def_path(def_id).to_string_no_crate_verbose()
         )
     }
+}
 
+impl<'tcx> TyCtxtAt<'tcx> {
     /// Create a new definition within the incr. comp. engine.
     pub fn create_def(
         self,
         parent: LocalDefId,
         data: hir::definitions::DefPathData,
-    ) -> TyCtxtFeed<'tcx> {
+    ) -> TyCtxtFeed<'tcx, LocalDefId> {
         // This function modifies `self.definitions` using a side-effect.
         // We need to ensure that these side effects are re-run by the incr. comp. engine.
         // Depending on the forever-red node will tell the graph that the calling query
@@ -1534,17 +1524,21 @@ pub fn create_def(
         // This is fine because:
         // - those queries are `eval_always` so we won't miss their result changing;
         // - this write will have happened before these queries are called.
-        let def_id = self.definitions.write().create_def(parent, data);
+        let key = self.untracked.definitions.write().create_def(parent, data);
 
-        TyCtxtFeed { tcx: self, def_id }
+        let feed = TyCtxtFeed { tcx: self.tcx, key };
+        feed.def_span(self.span);
+        feed
     }
+}
 
+impl<'tcx> TyCtxt<'tcx> {
     pub fn iter_local_def_id(self) -> impl Iterator<Item = LocalDefId> + 'tcx {
         // Create a dependency to the red node to be sure we re-execute this when the amount of
         // definitions change.
         self.dep_graph.read_index(DepNodeIndex::FOREVER_RED_NODE);
 
-        let definitions = &self.definitions;
+        let definitions = &self.untracked.definitions;
         std::iter::from_generator(|| {
             let mut i = 0;
 
@@ -1568,7 +1562,7 @@ pub fn def_path_table(self) -> &'tcx rustc_hir::definitions::DefPathTable {
 
         // 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();
+        let definitions = self.untracked.definitions.leak();
         definitions.def_path_table()
     }
 
@@ -1580,28 +1574,28 @@ pub fn def_path_hash_to_def_index_map(
         self.ensure().hir_crate(());
         // 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();
+        let definitions = self.untracked.definitions.leak();
         definitions.def_path_hash_to_def_index_map()
     }
 
     /// Note that this is *untracked* and should only be used within the query
     /// system if the result is otherwise tracked through queries
     pub fn cstore_untracked(self) -> &'tcx CrateStoreDyn {
-        &*self.untracked_resolutions.cstore
+        &*self.untracked.cstore
     }
 
     /// Note that this is *untracked* and should only be used within the query
     /// system if the result is otherwise tracked through queries
     #[inline]
     pub fn definitions_untracked(self) -> ReadGuard<'tcx, Definitions> {
-        self.definitions.read()
+        self.untracked.definitions.read()
     }
 
     /// Note that this is *untracked* and should only be used within the query
     /// system if the result is otherwise tracked through queries
     #[inline]
     pub fn source_span_untracked(self, def_id: LocalDefId) -> Span {
-        self.untracked_resolutions.source_span.get(def_id).copied().unwrap_or(DUMMY_SP)
+        self.untracked.source_span.get(def_id).copied().unwrap_or(DUMMY_SP)
     }
 
     #[inline(always)]
@@ -1609,14 +1603,7 @@ pub fn with_stable_hashing_context<R>(
         self,
         f: impl FnOnce(StableHashingContext<'_>) -> R,
     ) -> R {
-        let definitions = self.definitions_untracked();
-        let hcx = StableHashingContext::new(
-            self.sess,
-            &*definitions,
-            &*self.untracked_resolutions.cstore,
-            &self.untracked_resolutions.source_span,
-        );
-        f(hcx)
+        f(StableHashingContext::new(self.sess, &self.untracked))
     }
 
     pub fn serialize_query_result_cache(self, encoder: FileEncoder) -> FileEncodeResult {
@@ -2091,7 +2078,7 @@ pub fn go(fmt: &mut std::fmt::Formatter<'_>, tcx: TyCtxt<'_>) -> std::fmt::Resul
                 let shards = tcx.interners.type_.lock_shards();
                 let types = shards.iter().flat_map(|shard| shard.keys());
                 for &InternedInSet(t) in types {
-                    let variant = match t.kind {
+                    let variant = match t.internee {
                         ty::Bool | ty::Char | ty::Int(..) | ty::Uint(..) |
                             ty::Float(..) | ty::Str | ty::Never => continue,
                         ty::Error(_) => /* unimportant */ continue,
@@ -2201,51 +2188,26 @@ fn into_pointer(&self) -> *const () {
 }
 
 #[allow(rustc::usage_of_ty_tykind)]
-impl<'tcx> Borrow<TyKind<'tcx>> for InternedInSet<'tcx, WithStableHash<TyS<'tcx>>> {
-    fn borrow<'a>(&'a self) -> &'a TyKind<'tcx> {
-        &self.0.kind
-    }
-}
-
-impl<'tcx> PartialEq for InternedInSet<'tcx, WithStableHash<TyS<'tcx>>> {
-    fn eq(&self, other: &InternedInSet<'tcx, WithStableHash<TyS<'tcx>>>) -> bool {
-        // The `Borrow` trait requires that `x.borrow() == y.borrow()` equals
-        // `x == y`.
-        self.0.kind == other.0.kind
-    }
-}
-
-impl<'tcx> Eq for InternedInSet<'tcx, WithStableHash<TyS<'tcx>>> {}
-
-impl<'tcx> Hash for InternedInSet<'tcx, WithStableHash<TyS<'tcx>>> {
-    fn hash<H: Hasher>(&self, s: &mut H) {
-        // The `Borrow` trait requires that `x.borrow().hash(s) == x.hash(s)`.
-        self.0.kind.hash(s)
-    }
-}
-
-impl<'tcx> Borrow<Binder<'tcx, PredicateKind<'tcx>>>
-    for InternedInSet<'tcx, WithStableHash<PredicateS<'tcx>>>
-{
-    fn borrow<'a>(&'a self) -> &'a Binder<'tcx, PredicateKind<'tcx>> {
-        &self.0.kind
+impl<'tcx, T> Borrow<T> for InternedInSet<'tcx, WithCachedTypeInfo<T>> {
+    fn borrow<'a>(&'a self) -> &'a T {
+        &self.0.internee
     }
 }
 
-impl<'tcx> PartialEq for InternedInSet<'tcx, WithStableHash<PredicateS<'tcx>>> {
-    fn eq(&self, other: &InternedInSet<'tcx, WithStableHash<PredicateS<'tcx>>>) -> bool {
+impl<'tcx, T: PartialEq> PartialEq for InternedInSet<'tcx, WithCachedTypeInfo<T>> {
+    fn eq(&self, other: &InternedInSet<'tcx, WithCachedTypeInfo<T>>) -> bool {
         // The `Borrow` trait requires that `x.borrow() == y.borrow()` equals
         // `x == y`.
-        self.0.kind == other.0.kind
+        self.0.internee == other.0.internee
     }
 }
 
-impl<'tcx> Eq for InternedInSet<'tcx, WithStableHash<PredicateS<'tcx>>> {}
+impl<'tcx, T: Eq> Eq for InternedInSet<'tcx, WithCachedTypeInfo<T>> {}
 
-impl<'tcx> Hash for InternedInSet<'tcx, WithStableHash<PredicateS<'tcx>>> {
+impl<'tcx, T: Hash> Hash for InternedInSet<'tcx, WithCachedTypeInfo<T>> {
     fn hash<H: Hasher>(&self, s: &mut H) {
         // The `Borrow` trait requires that `x.borrow().hash(s) == x.hash(s)`.
-        self.0.kind.hash(s)
+        self.0.internee.hash(s)
     }
 }
 
@@ -2435,10 +2397,8 @@ pub fn mk_ty(self, st: TyKind<'tcx>) -> Ty<'tcx> {
         self.interners.intern_ty(
             st,
             self.sess,
-            &self.definitions.read(),
-            &*self.untracked_resolutions.cstore,
             // This is only used to create a stable hashing context.
-            &self.untracked_resolutions.source_span,
+            &self.untracked,
         )
     }
 
@@ -2447,10 +2407,8 @@ pub fn mk_predicate(self, binder: Binder<'tcx, PredicateKind<'tcx>>) -> Predicat
         self.interners.intern_predicate(
             binder,
             self.sess,
-            &self.definitions.read(),
-            &*self.untracked_resolutions.cstore,
             // This is only used to create a stable hashing context.
-            &self.untracked_resolutions.source_span,
+            &self.untracked,
         )
     }
 
@@ -3101,7 +3059,6 @@ fn ptr_eq<T, U>(t: *const T, u: *const U) -> bool {
 
 pub fn provide(providers: &mut ty::query::Providers) {
     providers.resolutions = |tcx, ()| &tcx.untracked_resolutions;
-    providers.resolver_for_lowering = |tcx, ()| &tcx.untracked_resolver_for_lowering;
     providers.module_reexports =
         |tcx, id| tcx.resolutions(()).reexport_map.get(&id).map(|v| &v[..]);
     providers.crate_name = |tcx, id| {
@@ -3133,4 +3090,6 @@ pub fn provide(providers: &mut ty::query::Providers) {
         // We want to check if the panic handler was defined in this crate
         tcx.lang_items().panic_impl().map_or(false, |did| did.is_local())
     };
+    providers.source_span =
+        |tcx, def_id| tcx.untracked.source_span.get(def_id).copied().unwrap_or(DUMMY_SP);
 }
index d83e17574a09423c249b54034a35339c6f9f1b04..4e113d72469c81d34eb10e25e952742ff9876174 100644 (file)
@@ -1,6 +1,6 @@
 use crate::traits::{ObligationCause, ObligationCauseCode};
 use crate::ty::diagnostics::suggest_constraining_type_param;
-use crate::ty::print::{FmtPrinter, Printer};
+use crate::ty::print::{with_forced_trimmed_paths, FmtPrinter, Printer};
 use crate::ty::{self, BoundRegionKind, Region, Ty, TyCtxt};
 use hir::def::DefKind;
 use rustc_errors::Applicability::{MachineApplicable, MaybeIncorrect};
@@ -162,17 +162,29 @@ fn report_maybe_different(
             ),
             RegionsPlaceholderMismatch => write!(f, "one type is more general than the other"),
             ArgumentSorts(values, _) | Sorts(values) => ty::tls::with(|tcx| {
-                report_maybe_different(
-                    f,
-                    &values.expected.sort_string(tcx),
-                    &values.found.sort_string(tcx),
-                )
+                let (mut expected, mut found) = with_forced_trimmed_paths!((
+                    values.expected.sort_string(tcx),
+                    values.found.sort_string(tcx),
+                ));
+                if expected == found {
+                    expected = values.expected.sort_string(tcx);
+                    found = values.found.sort_string(tcx);
+                }
+                report_maybe_different(f, &expected, &found)
             }),
             Traits(values) => ty::tls::with(|tcx| {
+                let (mut expected, mut found) = with_forced_trimmed_paths!((
+                    tcx.def_path_str(values.expected),
+                    tcx.def_path_str(values.found),
+                ));
+                if expected == found {
+                    expected = tcx.def_path_str(values.expected);
+                    found = tcx.def_path_str(values.found);
+                }
                 report_maybe_different(
                     f,
-                    &format!("trait `{}`", tcx.def_path_str(values.expected)),
-                    &format!("trait `{}`", tcx.def_path_str(values.found)),
+                    &format!("trait `{expected}`"),
+                    &format!("trait `{found}`"),
                 )
             }),
             IntMismatch(ref values) => {
@@ -986,23 +998,34 @@ fn constrain_associated_type_structured_suggestion(
     }
 
     pub fn short_ty_string(self, ty: Ty<'tcx>) -> (String, Option<PathBuf>) {
-        let length_limit = 50;
-        let type_limit = 4;
+        let width = self.sess.diagnostic_width();
+        let length_limit = width.saturating_sub(30);
+        let mut type_limit = 50;
         let regular = FmtPrinter::new(self, hir::def::Namespace::TypeNS)
             .pretty_print_type(ty)
             .expect("could not write to `String`")
             .into_buffer();
-        if regular.len() <= length_limit {
+        if regular.len() <= width {
             return (regular, None);
         }
-        let short = FmtPrinter::new_with_limit(
-            self,
-            hir::def::Namespace::TypeNS,
-            rustc_session::Limit(type_limit),
-        )
-        .pretty_print_type(ty)
-        .expect("could not write to `String`")
-        .into_buffer();
+        let mut short;
+        loop {
+            // Look for the longest properly trimmed path that still fits in lenght_limit.
+            short = with_forced_trimmed_paths!(
+                FmtPrinter::new_with_limit(
+                    self,
+                    hir::def::Namespace::TypeNS,
+                    rustc_session::Limit(type_limit),
+                )
+                .pretty_print_type(ty)
+                .expect("could not write to `String`")
+                .into_buffer()
+            );
+            if short.len() <= length_limit || type_limit == 0 {
+                break;
+            }
+            type_limit -= 1;
+        }
         if regular == short {
             return (regular, None);
         }
index a8da93e4c69b0d54303c31917dd4a22a02082021..2e70ac256a71973a768abfcd73cb943e66293cbf 100644 (file)
@@ -101,6 +101,20 @@ pub fn default_value<'tcx>(
             _ => None,
         }
     }
+
+    pub fn to_error<'tcx>(
+        &self,
+        tcx: TyCtxt<'tcx>,
+        preceding_substs: &[ty::GenericArg<'tcx>],
+    ) -> ty::GenericArg<'tcx> {
+        match &self.kind {
+            ty::GenericParamDefKind::Lifetime => tcx.lifetimes.re_static.into(),
+            ty::GenericParamDefKind::Type { .. } => tcx.ty_error().into(),
+            ty::GenericParamDefKind::Const { .. } => {
+                tcx.const_error(tcx.bound_type_of(self.def_id).subst(tcx, preceding_substs)).into()
+            }
+        }
+    }
 }
 
 #[derive(Default)]
@@ -220,6 +234,15 @@ pub fn param_at(&'tcx self, param_index: usize, tcx: TyCtxt<'tcx>) -> &'tcx Gene
         }
     }
 
+    pub fn params_to(&'tcx self, param_index: usize, tcx: TyCtxt<'tcx>) -> &'tcx [GenericParamDef] {
+        if let Some(index) = param_index.checked_sub(self.parent_count) {
+            &self.params[..index]
+        } else {
+            tcx.generics_of(self.parent.expect("parent_count > 0 but no parent?"))
+                .params_to(param_index, tcx)
+        }
+    }
+
     /// Returns the `GenericParamDef` associated with this `EarlyBoundRegion`.
     pub fn region_param(
         &'tcx self,
index dd4ab3e8d30bf24dff563a8273a90eb6ee2e2e73..659d99f025da03a469729b0f070448ac23cfc240 100644 (file)
@@ -9,6 +9,8 @@
 //!
 //! ["The `ty` module: representing types"]: https://rustc-dev-guide.rust-lang.org/ty.html
 
+#![allow(rustc::usage_of_ty_tykind)]
+
 pub use self::fold::{FallibleTypeFolder, TypeFoldable, TypeFolder, TypeSuperFoldable};
 pub use self::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitor};
 pub use self::AssocItemContainer::*;
 use rustc_attr as attr;
 use rustc_data_structures::fingerprint::Fingerprint;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet};
-use rustc_data_structures::intern::{Interned, WithStableHash};
+use rustc_data_structures::intern::Interned;
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 use rustc_data_structures::tagged_ptr::CopyTaggedPtr;
 use rustc_hir as hir;
 use rustc_hir::def::{CtorKind, CtorOf, DefKind, LifetimeRes, Res};
 use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, LocalDefIdMap};
-use rustc_hir::definitions::Definitions;
 use rustc_hir::Node;
 use rustc_index::vec::IndexVec;
 use rustc_macros::HashStable;
 use rustc_query_system::ich::StableHashingContext;
 use rustc_serialize::{Decodable, Encodable};
-use rustc_session::cstore::CrateStoreDyn;
+use rustc_session::cstore::Untracked;
 use rustc_span::hygiene::MacroKind;
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
 use rustc_span::{ExpnId, Span};
 use rustc_target::abi::{Align, Integer, IntegerType, VariantIdx};
 pub use rustc_target::abi::{ReprFlags, ReprOptions};
+use rustc_type_ir::WithCachedTypeInfo;
 pub use subst::*;
 pub use vtable::*;
 
@@ -82,8 +84,8 @@
 pub use self::context::{
     tls, CanonicalUserType, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations,
     CtxtInterners, DeducedParamAttrs, FreeRegionInfo, GeneratorDiagnosticData,
-    GeneratorInteriorTypeCause, GlobalCtxt, Lift, OnDiskCache, TyCtxt, TypeckResults, UserType,
-    UserTypeAnnotationIndex,
+    GeneratorInteriorTypeCause, GlobalCtxt, Lift, OnDiskCache, TyCtxt, TyCtxtFeed, TypeckResults,
+    UserType, UserTypeAnnotationIndex,
 };
 pub use self::instance::{Instance, InstanceDef, ShortInstance};
 pub use self::list::List;
 pub type RegisteredTools = FxHashSet<Ident>;
 
 pub struct ResolverOutputs {
-    pub definitions: Definitions,
     pub global_ctxt: ResolverGlobalCtxt,
     pub ast_lowering: ResolverAstLowering,
+    pub untracked: Untracked,
 }
 
 #[derive(Debug)]
 pub struct ResolverGlobalCtxt {
-    pub cstore: Box<CrateStoreDyn>,
     pub visibilities: FxHashMap<LocalDefId, Visibility>,
     /// This field is used to decide whether we should make `PRIVATE_IN_PUBLIC` a hard error.
     pub has_pub_restricted: bool,
     /// Item with a given `LocalDefId` was defined during macro expansion with ID `ExpnId`.
     pub expn_that_defined: FxHashMap<LocalDefId, ExpnId>,
-    /// Reference span for definitions.
-    pub source_span: IndexVec<LocalDefId, Span>,
     pub effective_visibilities: EffectiveVisibilities,
     pub extern_crate_map: FxHashMap<LocalDefId, CrateNum>,
     pub maybe_unused_trait_imports: FxIndexSet<LocalDefId>,
@@ -445,86 +444,22 @@ pub struct CReaderCacheKey {
     pub pos: usize,
 }
 
-/// Represents a type.
-///
-/// IMPORTANT:
-/// - This is a very "dumb" struct (with no derives and no `impls`).
-/// - Values of this type are always interned and thus unique, and are stored
-///   as an `Interned<TyS>`.
-/// - `Ty` (which contains a reference to a `Interned<TyS>`) or `Interned<TyS>`
-///   should be used everywhere instead of `TyS`. In particular, `Ty` has most
-///   of the relevant methods.
-#[derive(PartialEq, Eq, PartialOrd, Ord)]
-#[allow(rustc::usage_of_ty_tykind)]
-pub(crate) struct TyS<'tcx> {
-    /// This field shouldn't be used directly and may be removed in the future.
-    /// Use `Ty::kind()` instead.
-    kind: TyKind<'tcx>,
-
-    /// This field provides fast access to information that is also contained
-    /// in `kind`.
-    ///
-    /// This field shouldn't be used directly and may be removed in the future.
-    /// Use `Ty::flags()` instead.
-    flags: TypeFlags,
-
-    /// This field provides fast access to information that is also contained
-    /// in `kind`.
-    ///
-    /// This is a kind of confusing thing: it stores the smallest
-    /// binder such that
-    ///
-    /// (a) the binder itself captures nothing but
-    /// (b) all the late-bound things within the type are captured
-    ///     by some sub-binder.
-    ///
-    /// So, for a type without any late-bound things, like `u32`, this
-    /// will be *innermost*, because that is the innermost binder that
-    /// captures nothing. But for a type `&'D u32`, where `'D` is a
-    /// late-bound region with De Bruijn index `D`, this would be `D + 1`
-    /// -- the binder itself does not capture `D`, but `D` is captured
-    /// by an inner binder.
-    ///
-    /// We call this concept an "exclusive" binder `D` because all
-    /// De Bruijn indices within the type are contained within `0..D`
-    /// (exclusive).
-    outer_exclusive_binder: ty::DebruijnIndex,
-}
-
-/// Use this rather than `TyS`, whenever possible.
+/// Use this rather than `TyKind`, whenever possible.
 #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, HashStable)]
 #[rustc_diagnostic_item = "Ty"]
 #[rustc_pass_by_value]
-pub struct Ty<'tcx>(Interned<'tcx, WithStableHash<TyS<'tcx>>>);
+pub struct Ty<'tcx>(Interned<'tcx, WithCachedTypeInfo<TyKind<'tcx>>>);
 
 impl<'tcx> TyCtxt<'tcx> {
     /// A "bool" type used in rustc_mir_transform unit tests when we
     /// have not spun up a TyCtxt.
-    pub const BOOL_TY_FOR_UNIT_TESTING: Ty<'tcx> = Ty(Interned::new_unchecked(&WithStableHash {
-        internee: TyS {
-            kind: ty::Bool,
+    pub const BOOL_TY_FOR_UNIT_TESTING: Ty<'tcx> =
+        Ty(Interned::new_unchecked(&WithCachedTypeInfo {
+            internee: ty::Bool,
+            stable_hash: Fingerprint::ZERO,
             flags: TypeFlags::empty(),
             outer_exclusive_binder: DebruijnIndex::from_usize(0),
-        },
-        stable_hash: Fingerprint::ZERO,
-    }));
-}
-
-impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for TyS<'tcx> {
-    #[inline]
-    fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
-        let TyS {
-            kind,
-
-            // The other fields just provide fast access to information that is
-            // also contained in `kind`, so no need to hash them.
-            flags: _,
-
-            outer_exclusive_binder: _,
-        } = self;
-
-        kind.hash_stable(hcx, hasher)
-    }
+        }));
 }
 
 impl ty::EarlyBoundRegion {
@@ -535,28 +470,18 @@ pub fn has_name(&self) -> bool {
     }
 }
 
-/// Represents a predicate.
-///
-/// See comments on `TyS`, which apply here too (albeit for
-/// `PredicateS`/`Predicate` rather than `TyS`/`Ty`).
-#[derive(Debug)]
-pub(crate) struct PredicateS<'tcx> {
-    kind: Binder<'tcx, PredicateKind<'tcx>>,
-    flags: TypeFlags,
-    /// See the comment for the corresponding field of [TyS].
-    outer_exclusive_binder: ty::DebruijnIndex,
-}
-
-/// Use this rather than `PredicateS`, whenever possible.
+/// Use this rather than `PredicateKind`, whenever possible.
 #[derive(Clone, Copy, PartialEq, Eq, Hash, HashStable)]
 #[rustc_pass_by_value]
-pub struct Predicate<'tcx>(Interned<'tcx, WithStableHash<PredicateS<'tcx>>>);
+pub struct Predicate<'tcx>(
+    Interned<'tcx, WithCachedTypeInfo<ty::Binder<'tcx, PredicateKind<'tcx>>>>,
+);
 
 impl<'tcx> Predicate<'tcx> {
     /// Gets the inner `Binder<'tcx, PredicateKind<'tcx>>`.
     #[inline]
     pub fn kind(self) -> Binder<'tcx, PredicateKind<'tcx>> {
-        self.0.kind
+        self.0.internee
     }
 
     #[inline(always)]
@@ -631,21 +556,6 @@ pub fn allow_normalization(self) -> bool {
     }
 }
 
-impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for PredicateS<'tcx> {
-    fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
-        let PredicateS {
-            ref kind,
-
-            // The other fields just provide fast access to information that is
-            // also contained in `kind`, so no need to hash them.
-            flags: _,
-            outer_exclusive_binder: _,
-        } = self;
-
-        kind.hash_stable(hcx, hasher);
-    }
-}
-
 impl rustc_errors::IntoDiagnosticArg for Predicate<'_> {
     fn into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue<'static> {
         rustc_errors::DiagnosticArgValue::Str(std::borrow::Cow::Owned(self.to_string()))
@@ -1028,7 +938,7 @@ pub fn unpack(self) -> TermKind<'tcx> {
         unsafe {
             match ptr & TAG_MASK {
                 TYPE_TAG => TermKind::Ty(Ty(Interned::new_unchecked(
-                    &*((ptr & !TAG_MASK) as *const WithStableHash<ty::TyS<'tcx>>),
+                    &*((ptr & !TAG_MASK) as *const WithCachedTypeInfo<ty::TyKind<'tcx>>),
                 ))),
                 CONST_TAG => TermKind::Const(ty::Const(Interned::new_unchecked(
                     &*((ptr & !TAG_MASK) as *const ty::ConstS<'tcx>),
@@ -1072,7 +982,7 @@ fn pack(self) -> Term<'tcx> {
             TermKind::Ty(ty) => {
                 // Ensure we can use the tag bits.
                 assert_eq!(mem::align_of_val(&*ty.0.0) & TAG_MASK, 0);
-                (TYPE_TAG, ty.0.0 as *const WithStableHash<ty::TyS<'tcx>> as usize)
+                (TYPE_TAG, ty.0.0 as *const WithCachedTypeInfo<ty::TyKind<'tcx>> as usize)
             }
             TermKind::Const(ct) => {
                 // Ensure we can use the tag bits.
@@ -1150,8 +1060,8 @@ fn to_poly_trait_ref(&self) -> PolyTraitRef<'tcx> {
     }
 }
 
-pub trait ToPredicate<'tcx, Predicate> {
-    fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate;
+pub trait ToPredicate<'tcx, P = Predicate<'tcx>> {
+    fn to_predicate(self, tcx: TyCtxt<'tcx>) -> P;
 }
 
 impl<'tcx, T> ToPredicate<'tcx, T> for T {
@@ -1160,21 +1070,21 @@ fn to_predicate(self, _tcx: TyCtxt<'tcx>) -> T {
     }
 }
 
-impl<'tcx> ToPredicate<'tcx, Predicate<'tcx>> for Binder<'tcx, PredicateKind<'tcx>> {
+impl<'tcx> ToPredicate<'tcx> for Binder<'tcx, PredicateKind<'tcx>> {
     #[inline(always)]
     fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> {
         tcx.mk_predicate(self)
     }
 }
 
-impl<'tcx> ToPredicate<'tcx, Predicate<'tcx>> for Clause<'tcx> {
+impl<'tcx> ToPredicate<'tcx> for Clause<'tcx> {
     #[inline(always)]
     fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> {
         tcx.mk_predicate(ty::Binder::dummy(ty::PredicateKind::Clause(self)))
     }
 }
 
-impl<'tcx> ToPredicate<'tcx, Predicate<'tcx>> for Binder<'tcx, TraitRef<'tcx>> {
+impl<'tcx> ToPredicate<'tcx> for Binder<'tcx, TraitRef<'tcx>> {
     #[inline(always)]
     fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> {
         let pred: PolyTraitPredicate<'tcx> = self.to_predicate(tcx);
@@ -1193,25 +1103,25 @@ fn to_predicate(self, _: TyCtxt<'tcx>) -> PolyTraitPredicate<'tcx> {
     }
 }
 
-impl<'tcx> ToPredicate<'tcx, Predicate<'tcx>> for PolyTraitPredicate<'tcx> {
+impl<'tcx> ToPredicate<'tcx> for PolyTraitPredicate<'tcx> {
     fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> {
         self.map_bound(|p| PredicateKind::Clause(Clause::Trait(p))).to_predicate(tcx)
     }
 }
 
-impl<'tcx> ToPredicate<'tcx, Predicate<'tcx>> for PolyRegionOutlivesPredicate<'tcx> {
+impl<'tcx> ToPredicate<'tcx> for PolyRegionOutlivesPredicate<'tcx> {
     fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> {
         self.map_bound(|p| PredicateKind::Clause(Clause::RegionOutlives(p))).to_predicate(tcx)
     }
 }
 
-impl<'tcx> ToPredicate<'tcx, Predicate<'tcx>> for PolyTypeOutlivesPredicate<'tcx> {
+impl<'tcx> ToPredicate<'tcx> for PolyTypeOutlivesPredicate<'tcx> {
     fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> {
         self.map_bound(|p| PredicateKind::Clause(Clause::TypeOutlives(p))).to_predicate(tcx)
     }
 }
 
-impl<'tcx> ToPredicate<'tcx, Predicate<'tcx>> for PolyProjectionPredicate<'tcx> {
+impl<'tcx> ToPredicate<'tcx> for PolyProjectionPredicate<'tcx> {
     fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> {
         self.map_bound(|p| PredicateKind::Clause(Clause::Projection(p))).to_predicate(tcx)
     }
@@ -2228,10 +2138,6 @@ pub fn opt_associated_item(self, def_id: DefId) -> Option<&'tcx AssocItem> {
         }
     }
 
-    pub fn field_index(self, hir_id: hir::HirId, typeck_results: &TypeckResults<'_>) -> usize {
-        typeck_results.field_indices().get(hir_id).cloned().expect("no index for a field")
-    }
-
     pub fn find_field_index(self, ident: Ident, variant: &VariantDef) -> Option<usize> {
         variant
             .fields
@@ -2692,8 +2598,7 @@ mod size_asserts {
     use super::*;
     use rustc_data_structures::static_assert_size;
     // tidy-alphabetical-start
-    static_assert_size!(PredicateS<'_>, 48);
-    static_assert_size!(TyS<'_>, 40);
-    static_assert_size!(WithStableHash<TyS<'_>>, 56);
+    static_assert_size!(PredicateKind<'_>, 32);
+    static_assert_size!(WithCachedTypeInfo<TyKind<'_>>, 56);
     // tidy-alphabetical-end
 }
index 5303341ba443c6c285fc170b96aa81535641b3ad..6bf42f81f131e6e447537bd290a3263fb054f715 100644 (file)
@@ -10,7 +10,7 @@
 use rustc_hir as hir;
 use rustc_hir::def::{self, CtorKind, DefKind, Namespace};
 use rustc_hir::def_id::{DefId, DefIdSet, CRATE_DEF_ID, LOCAL_CRATE};
-use rustc_hir::definitions::{DefPathData, DefPathDataName, DisambiguatedDefPathData};
+use rustc_hir::definitions::{DefKey, DefPathData, DefPathDataName, DisambiguatedDefPathData};
 use rustc_hir::LangItem;
 use rustc_session::config::TrimmedDefPaths;
 use rustc_session::cstore::{ExternCrate, ExternCrateSource};
@@ -23,7 +23,6 @@
 use std::cell::Cell;
 use std::char;
 use std::collections::BTreeMap;
-use std::convert::TryFrom;
 use std::fmt::{self, Write as _};
 use std::iter;
 use std::ops::{ControlFlow, Deref, DerefMut};
@@ -63,6 +62,7 @@ macro_rules! scoped_cx {
     static FORCE_IMPL_FILENAME_LINE: Cell<bool> = const { Cell::new(false) };
     static SHOULD_PREFIX_WITH_CRATE: Cell<bool> = const { Cell::new(false) };
     static NO_TRIMMED_PATH: Cell<bool> = const { Cell::new(false) };
+    static FORCE_TRIMMED_PATH: Cell<bool> = const { Cell::new(false) };
     static NO_QUERIES: Cell<bool> = const { Cell::new(false) };
     static NO_VISIBLE_PATH: Cell<bool> = const { Cell::new(false) };
 }
@@ -116,6 +116,7 @@ fn drop(&mut self) {
     /// of various rustc types, for example `std::vec::Vec` would be trimmed to `Vec`,
     /// if no other `Vec` is found.
     fn with_no_trimmed_paths(NoTrimmedGuard, NO_TRIMMED_PATH);
+    fn with_forced_trimmed_paths(ForceTrimmedGuard, FORCE_TRIMMED_PATH);
     /// Prevent selection of visible paths. `Display` impl of DefId will prefer
     /// visible (public) reexports of types as paths.
     fn with_no_visible_paths(NoVisibleGuard, NO_VISIBLE_PATH);
@@ -295,11 +296,89 @@ fn try_print_visible_def_path(self, def_id: DefId) -> Result<(Self, bool), Self:
         self.try_print_visible_def_path_recur(def_id, &mut callers)
     }
 
+    // Given a `DefId`, produce a short name. For types and traits, it prints *only* its name,
+    // For associated items on traits it prints out the trait's name and the associated item's name.
+    // For enum variants, if they have an unique name, then we only print the name, otherwise we
+    // print the enum name and the variant name. Otherwise, we do not print anything and let the
+    // caller use the `print_def_path` fallback.
+    fn force_print_trimmed_def_path(
+        mut self,
+        def_id: DefId,
+    ) -> Result<(Self::Path, bool), Self::Error> {
+        let key = self.tcx().def_key(def_id);
+        let visible_parent_map = self.tcx().visible_parent_map(());
+        let kind = self.tcx().def_kind(def_id);
+
+        let get_local_name = |this: &Self, name, def_id, key: DefKey| {
+            if let Some(visible_parent) = visible_parent_map.get(&def_id)
+                && let actual_parent = this.tcx().opt_parent(def_id)
+                && let DefPathData::TypeNs(_) = key.disambiguated_data.data
+                && Some(*visible_parent) != actual_parent
+            {
+                this
+                    .tcx()
+                    .module_children(visible_parent)
+                    .iter()
+                    .filter(|child| child.res.opt_def_id() == Some(def_id))
+                    .find(|child| child.vis.is_public() && child.ident.name != kw::Underscore)
+                    .map(|child| child.ident.name)
+                    .unwrap_or(name)
+            } else {
+                name
+            }
+        };
+        if let DefKind::Variant = kind
+            && let Some(symbol) = self.tcx().trimmed_def_paths(()).get(&def_id)
+        {
+            // If `Assoc` is unique, we don't want to talk about `Trait::Assoc`.
+            self.write_str(get_local_name(&self, *symbol, def_id, key).as_str())?;
+            return Ok((self, true));
+        }
+        if let Some(symbol) = key.get_opt_name() {
+            if let DefKind::AssocConst | DefKind::AssocFn | DefKind::AssocTy = kind
+                && let Some(parent) = self.tcx().opt_parent(def_id)
+                && let parent_key = self.tcx().def_key(parent)
+                && let Some(symbol) = parent_key.get_opt_name()
+            {
+                // Trait
+                self.write_str(get_local_name(&self, symbol, parent, parent_key).as_str())?;
+                self.write_str("::")?;
+            } else if let DefKind::Variant = kind
+                && let Some(parent) = self.tcx().opt_parent(def_id)
+                && let parent_key = self.tcx().def_key(parent)
+                && let Some(symbol) = parent_key.get_opt_name()
+            {
+                // Enum
+
+                // For associated items and variants, we want the "full" path, namely, include
+                // the parent type in the path. For example, `Iterator::Item`.
+                self.write_str(get_local_name(&self, symbol, parent, parent_key).as_str())?;
+                self.write_str("::")?;
+            } else if let DefKind::Struct | DefKind::Union | DefKind::Enum | DefKind::Trait
+                | DefKind::TyAlias | DefKind::Fn | DefKind::Const | DefKind::Static(_) = kind
+            {
+            } else {
+                // If not covered above, like for example items out of `impl` blocks, fallback.
+                return Ok((self, false));
+            }
+            self.write_str(get_local_name(&self, symbol, def_id, key).as_str())?;
+            return Ok((self, true));
+        }
+        Ok((self, false))
+    }
+
     /// Try to see if this path can be trimmed to a unique symbol name.
     fn try_print_trimmed_def_path(
         mut self,
         def_id: DefId,
     ) -> Result<(Self::Path, bool), Self::Error> {
+        if FORCE_TRIMMED_PATH.with(|flag| flag.get()) {
+            let (s, trimmed) = self.force_print_trimmed_def_path(def_id)?;
+            if trimmed {
+                return Ok((s, true));
+            }
+            self = s;
+        }
         if !self.tcx().sess.opts.unstable_opts.trim_diagnostic_paths
             || matches!(self.tcx().sess.opts.trimmed_def_paths, TrimmedDefPaths::Never)
             || NO_TRIMMED_PATH.with(|flag| flag.get())
index 47c1379b308ebd3fa3dcf1b9e7bd5e78c987265b..642900d3ab4299108844ded337ec7fb8e5c64b6b 100644 (file)
@@ -328,13 +328,25 @@ fn $name(
     };
 }
 
+macro_rules! hash_result {
+    ([]) => {{
+        Some(dep_graph::hash_result)
+    }};
+    ([(no_hash) $($rest:tt)*]) => {{
+        None
+    }};
+    ([$other:tt $($modifiers:tt)*]) => {
+        hash_result!([$($modifiers)*])
+    };
+}
+
 macro_rules! define_feedable {
     ($($(#[$attr:meta])* [$($modifiers:tt)*] fn $name:ident($($K:tt)*) -> $V:ty,)*) => {
-        impl<'tcx> TyCtxtFeed<'tcx> {
-            $($(#[$attr])*
+        $(impl<'tcx, K: IntoQueryParam<$($K)*> + Copy> TyCtxtFeed<'tcx, K> {
+            $(#[$attr])*
             #[inline(always)]
             pub fn $name(self, value: $V) -> query_stored::$name<'tcx> {
-                let key = self.def_id().into_query_param();
+                let key = self.key().into_query_param();
                 opt_remap_env_constness!([$($modifiers)*][key]);
 
                 let tcx = self.tcx;
@@ -344,12 +356,10 @@ pub fn $name(self, value: $V) -> query_stored::$name<'tcx> {
 
                 match cached {
                     Ok(old) => {
-                        assert_eq!(
-                            value, old,
-                            "Trying to feed an already recorded value for query {} key={key:?}",
+                        bug!(
+                            "Trying to feed an already recorded value for query {} key={key:?}:\nold value: {old:?}\nnew value: {value:?}",
                             stringify!($name),
                         );
-                        return old;
                     }
                     Err(()) => (),
                 }
@@ -360,11 +370,11 @@ pub fn $name(self, value: $V) -> query_stored::$name<'tcx> {
                     tcx,
                     key,
                     &value,
-                    dep_graph::hash_result,
+                    hash_result!([$($modifiers)*]),
                 );
                 cache.complete(key, value, dep_node_index)
-            })*
-        }
+            }
+        })*
     }
 }
 
index 5984686044b7340dfb5a3f57eaba07990613384c..9cbda95a4df7a7f1e582dadbcf021829f45791a4 100644 (file)
@@ -722,8 +722,17 @@ pub fn with_self_ty(&self, tcx: TyCtxt<'tcx>, self_ty: Ty<'tcx>) -> ty::Predicat
                 self.rebind(p.with_self_ty(tcx, self_ty)).to_predicate(tcx)
             }
             ExistentialPredicate::AutoTrait(did) => {
-                let trait_ref = self.rebind(tcx.mk_trait_ref(did, [self_ty]));
-                trait_ref.without_const().to_predicate(tcx)
+                let generics = tcx.generics_of(did);
+                let trait_ref = if generics.params.len() == 1 {
+                    tcx.mk_trait_ref(did, [self_ty])
+                } else {
+                    // If this is an ill-formed auto trait, then synthesize
+                    // new error substs for the missing generics.
+                    let err_substs =
+                        ty::InternalSubsts::extend_with_error(tcx, did, &[self_ty.into()]);
+                    tcx.mk_trait_ref(did, err_substs)
+                };
+                self.rebind(trait_ref).without_const().to_predicate(tcx)
             }
         }
     }
@@ -1602,7 +1611,7 @@ pub fn is_var(self) -> bool {
 impl<'tcx> Ty<'tcx> {
     #[inline(always)]
     pub fn kind(self) -> &'tcx TyKind<'tcx> {
-        &self.0.0.kind
+        &self.0.0
     }
 
     #[inline(always)]
index 141c8354c183d65ace6d553f10172f6ccbf2982b..a1b084a5e891eca1bb2bf780597bae2fb06cbb40 100644 (file)
@@ -6,10 +6,11 @@
 use crate::ty::visit::{TypeVisitable, TypeVisitor};
 use crate::ty::{self, Lift, List, ParamConst, Ty, TyCtxt};
 
-use rustc_data_structures::intern::{Interned, WithStableHash};
+use rustc_data_structures::intern::Interned;
 use rustc_hir::def_id::DefId;
 use rustc_macros::HashStable;
 use rustc_serialize::{self, Decodable, Encodable};
+use rustc_type_ir::WithCachedTypeInfo;
 use smallvec::SmallVec;
 
 use core::intrinsics;
@@ -84,7 +85,7 @@ fn pack(self) -> GenericArg<'tcx> {
             GenericArgKind::Type(ty) => {
                 // Ensure we can use the tag bits.
                 assert_eq!(mem::align_of_val(&*ty.0.0) & TAG_MASK, 0);
-                (TYPE_TAG, ty.0.0 as *const WithStableHash<ty::TyS<'tcx>> as usize)
+                (TYPE_TAG, ty.0.0 as *const WithCachedTypeInfo<ty::TyKind<'tcx>> as usize)
             }
             GenericArgKind::Const(ct) => {
                 // Ensure we can use the tag bits.
@@ -162,7 +163,7 @@ pub fn unpack(self) -> GenericArgKind<'tcx> {
                     &*((ptr & !TAG_MASK) as *const ty::RegionKind<'tcx>),
                 ))),
                 TYPE_TAG => GenericArgKind::Type(Ty(Interned::new_unchecked(
-                    &*((ptr & !TAG_MASK) as *const WithStableHash<ty::TyS<'tcx>>),
+                    &*((ptr & !TAG_MASK) as *const WithCachedTypeInfo<ty::TyKind<'tcx>>),
                 ))),
                 CONST_TAG => GenericArgKind::Const(ty::Const(Interned::new_unchecked(
                     &*((ptr & !TAG_MASK) as *const ty::ConstS<'tcx>),
@@ -352,6 +353,22 @@ pub fn fill_single<F>(
         }
     }
 
+    // Extend an `original_substs` list to the full number of substs expected by `def_id`,
+    // filling in the missing parameters with error ty/ct or 'static regions.
+    pub fn extend_with_error(
+        tcx: TyCtxt<'tcx>,
+        def_id: DefId,
+        original_substs: &[GenericArg<'tcx>],
+    ) -> SubstsRef<'tcx> {
+        ty::InternalSubsts::for_item(tcx, def_id, |def, substs| {
+            if let Some(subst) = original_substs.get(def.index as usize) {
+                *subst
+            } else {
+                def.to_error(tcx, substs)
+            }
+        })
+    }
+
     #[inline]
     pub fn types(&'tcx self) -> impl DoubleEndedIterator<Item = Ty<'tcx>> + 'tcx {
         self.iter()
index 47c1ce8075674acd461a2cd8d90da3ca73dd76e4..9ea8dc6e69fdde0b172103282cd1c384bd3fb5b2 100644 (file)
@@ -1,6 +1,7 @@
 //! Miscellaneous type-system utilities that are too small to deserve their own modules.
 
 use crate::middle::codegen_fn_attrs::CodegenFnAttrFlags;
+use crate::mir;
 use crate::ty::layout::IntegerExt;
 use crate::ty::{
     self, DefIdTree, FallibleTypeFolder, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable,
@@ -15,6 +16,7 @@
 use rustc_hir::def::{CtorOf, DefKind, Res};
 use rustc_hir::def_id::DefId;
 use rustc_index::bit_set::GrowableBitSet;
+use rustc_index::vec::{Idx, IndexVec};
 use rustc_macros::HashStable;
 use rustc_span::{sym, DUMMY_SP};
 use rustc_target::abi::{Integer, IntegerType, Size, TargetDataLayout};
@@ -692,6 +694,80 @@ pub fn bound_explicit_predicates_of(
     pub fn bound_impl_subject(self, def_id: DefId) -> ty::EarlyBinder<ty::ImplSubject<'tcx>> {
         ty::EarlyBinder(self.impl_subject(def_id))
     }
+
+    /// Returns names of captured upvars for closures and generators.
+    ///
+    /// Here are some examples:
+    ///  - `name__field1__field2` when the upvar is captured by value.
+    ///  - `_ref__name__field` when the upvar is captured by reference.
+    ///
+    /// For generators this only contains upvars that are shared by all states.
+    pub fn closure_saved_names_of_captured_variables(
+        self,
+        def_id: DefId,
+    ) -> SmallVec<[String; 16]> {
+        let body = self.optimized_mir(def_id);
+
+        body.var_debug_info
+            .iter()
+            .filter_map(|var| {
+                let is_ref = match var.value {
+                    mir::VarDebugInfoContents::Place(place)
+                        if place.local == mir::Local::new(1) =>
+                    {
+                        // The projection is either `[.., Field, Deref]` or `[.., Field]`. It
+                        // implies whether the variable is captured by value or by reference.
+                        matches!(place.projection.last().unwrap(), mir::ProjectionElem::Deref)
+                    }
+                    _ => return None,
+                };
+                let prefix = if is_ref { "_ref__" } else { "" };
+                Some(prefix.to_owned() + var.name.as_str())
+            })
+            .collect()
+    }
+
+    // FIXME(eddyb) maybe precompute this? Right now it's computed once
+    // per generator monomorphization, but it doesn't depend on substs.
+    pub fn generator_layout_and_saved_local_names(
+        self,
+        def_id: DefId,
+    ) -> (
+        &'tcx ty::GeneratorLayout<'tcx>,
+        IndexVec<mir::GeneratorSavedLocal, Option<rustc_span::Symbol>>,
+    ) {
+        let tcx = self;
+        let body = tcx.optimized_mir(def_id);
+        let generator_layout = body.generator_layout().unwrap();
+        let mut generator_saved_local_names =
+            IndexVec::from_elem(None, &generator_layout.field_tys);
+
+        let state_arg = mir::Local::new(1);
+        for var in &body.var_debug_info {
+            let mir::VarDebugInfoContents::Place(place) = &var.value else { continue };
+            if place.local != state_arg {
+                continue;
+            }
+            match place.projection[..] {
+                [
+                    // Deref of the `Pin<&mut Self>` state argument.
+                    mir::ProjectionElem::Field(..),
+                    mir::ProjectionElem::Deref,
+                    // Field of a variant of the state.
+                    mir::ProjectionElem::Downcast(_, variant),
+                    mir::ProjectionElem::Field(field, _),
+                ] => {
+                    let name = &mut generator_saved_local_names
+                        [generator_layout.variant_fields[variant][field]];
+                    if name.is_none() {
+                        name.replace(var.name);
+                    }
+                }
+                _ => {}
+            }
+        }
+        (generator_layout, generator_saved_local_names)
+    }
 }
 
 struct OpaqueTypeExpander<'tcx> {
index 6eae94511e4d63c05f1a508da14027ac07cf0399..802925dfb043e3eafb4f70304a50cf359f0cb78b 100644 (file)
@@ -1,4 +1,3 @@
-use std::convert::TryFrom;
 use std::fmt;
 
 use crate::mir::interpret::{alloc_range, AllocId, Allocation, Pointer, Scalar};
index f4562cdfb88dcfdfa07c488896a761f3fef5872f..70b98e59a8beab34f6e801b412526d6d5ac15aed 100644 (file)
@@ -32,13 +32,23 @@ fn from_cycle_error(tcx: TyCtxt<'tcx>, _: &[QueryInfo]) -> Self {
 }
 
 impl<'tcx> Value<TyCtxt<'tcx>> for ty::Binder<'_, ty::FnSig<'_>> {
-    fn from_cycle_error(tcx: TyCtxt<'tcx>, _: &[QueryInfo]) -> Self {
+    fn from_cycle_error(tcx: TyCtxt<'tcx>, stack: &[QueryInfo]) -> Self {
         let err = tcx.ty_error();
-        // FIXME(compiler-errors): It would be nice if we could get the
-        // query key, so we could at least generate a fn signature that
-        // has the right arity.
+
+        let arity = if let Some(frame) = stack.get(0)
+            && frame.query.name == "fn_sig"
+            && let Some(def_id) = frame.query.def_id
+            && let Some(node) = tcx.hir().get_if_local(def_id)
+            && let Some(sig) = node.fn_sig()
+        {
+            sig.decl.inputs.len() + sig.decl.implicit_self.has_implicit_self() as usize
+        } else {
+            tcx.sess.abort_if_errors();
+            unreachable!()
+        };
+
         let fn_sig = ty::Binder::dummy(tcx.mk_fn_sig(
-            [].into_iter(),
+            std::iter::repeat(err).take(arity),
             err,
             false,
             rustc_hir::Unsafety::Normal,
index 2412824efeb751c305af719d5fb4dccd3d2729e7..eb021f477573c165847eb5159def1aff24535c7c 100644 (file)
@@ -57,7 +57,7 @@ pub(super) fn build_custom_mir<'tcx>(
         is_polymorphic: false,
         tainted_by_errors: None,
         injection_phase: None,
-        pass_count: 1,
+        pass_count: 0,
     };
 
     body.local_decls.push(LocalDecl::new(return_ty, return_ty_span));
index 218a26e62797dc97b0fe5f559ead5374613506de..38b1fa91d0a6794ec3cb6dc42ef0330607542825 100644 (file)
@@ -183,7 +183,7 @@ pub(crate) fn expr_into_dest(
                     LogicalOp::And => (else_block, shortcircuit_block),
                     LogicalOp::Or => (shortcircuit_block, else_block),
                 };
-                let term = TerminatorKind::if_(this.tcx, lhs, blocks.0, blocks.1);
+                let term = TerminatorKind::if_(lhs, blocks.0, blocks.1);
                 this.cfg.terminate(block, source_info, term);
 
                 this.cfg.push_assign_constant(
index 691cbee2c731911acf2997bea4754b5d54c9ee16..7edcd46a34f293a542e1f2df59bc6f55f07a7bce 100644 (file)
@@ -30,7 +30,6 @@
 mod util;
 
 use std::borrow::Borrow;
-use std::convert::TryFrom;
 use std::mem;
 
 impl<'a, 'tcx> Builder<'a, 'tcx> {
@@ -95,7 +94,7 @@ pub(crate) fn then_else_break(
 
                 let then_block = this.cfg.start_new_block();
                 let else_block = this.cfg.start_new_block();
-                let term = TerminatorKind::if_(this.tcx, operand, then_block, else_block);
+                let term = TerminatorKind::if_(operand, then_block, else_block);
 
                 let source_info = this.source_info(expr_span);
                 this.cfg.terminate(block, source_info, term);
index 58513bde2aa2a09fdcff2d16b02ec26bd2af02e4..6d5a98342d2936730549754f62fcacdadd06bcae 100644 (file)
@@ -203,7 +203,6 @@ pub(super) fn perform_test(
                     self.source_info(match_start_span),
                     TerminatorKind::SwitchInt {
                         discr: Operand::Move(discr),
-                        switch_ty: discr_ty,
                         targets: switch_targets,
                     },
                 );
@@ -221,7 +220,7 @@ pub(super) fn perform_test(
                         0 => (second_bb, first_bb),
                         v => span_bug!(test.span, "expected boolean value but got {:?}", v),
                     };
-                    TerminatorKind::if_(self.tcx, Operand::Copy(place), true_bb, false_bb)
+                    TerminatorKind::if_(Operand::Copy(place), true_bb, false_bb)
                 } else {
                     // The switch may be inexhaustive so we have a catch all block
                     debug_assert_eq!(options.len() + 1, target_blocks.len());
@@ -232,7 +231,6 @@ pub(super) fn perform_test(
                     );
                     TerminatorKind::SwitchInt {
                         discr: Operand::Copy(place),
-                        switch_ty,
                         targets: switch_targets,
                     }
                 };
@@ -378,7 +376,7 @@ fn compare(
         self.cfg.terminate(
             block,
             source_info,
-            TerminatorKind::if_(self.tcx, Operand::Move(result), success_block, fail_block),
+            TerminatorKind::if_(Operand::Move(result), success_block, fail_block),
         );
     }
 
@@ -482,7 +480,7 @@ fn non_scalar_compare(
         self.cfg.terminate(
             eq_block,
             source_info,
-            TerminatorKind::if_(self.tcx, Operand::Move(eq_result), success_block, fail_block),
+            TerminatorKind::if_(Operand::Move(eq_result), success_block, fail_block),
         );
     }
 
index bd435f9ab0095a4b86e10703a3127c31bbd068b5..cbd494862a01f09ee0debdb8d4bd0eacae39f3d9 100644 (file)
@@ -7,7 +7,6 @@
 use rustc_middle::ty;
 use rustc_middle::ty::TypeVisitable;
 use smallvec::SmallVec;
-use std::convert::TryInto;
 
 impl<'a, 'tcx> Builder<'a, 'tcx> {
     pub(crate) fn field_match_pairs<'pat>(
index b456e2aa37a2791fae3f40a8868c9ff70bcea9b7..007f3b55ec8bb156b6c53c338fdfbbfacd3641f8 100644 (file)
@@ -948,20 +948,12 @@ fn set_correct_source_scope_for_arg(
         original_source_scope: SourceScope,
         pattern_span: Span,
     ) {
-        let tcx = self.tcx;
-        let current_root = tcx.maybe_lint_level_root_bounded(arg_hir_id, self.hir_id);
-        let parent_root = tcx.maybe_lint_level_root_bounded(
-            self.source_scopes[original_source_scope]
-                .local_data
-                .as_ref()
-                .assert_crate_local()
-                .lint_root,
-            self.hir_id,
-        );
-        if current_root != parent_root {
-            self.source_scope =
-                self.new_source_scope(pattern_span, LintLevel::Explicit(current_root), None);
-        }
+        let parent_id = self.source_scopes[original_source_scope]
+            .local_data
+            .as_ref()
+            .assert_crate_local()
+            .lint_root;
+        self.maybe_new_source_scope(pattern_span, None, arg_hir_id, parent_id);
     }
 
     fn get_unit_temp(&mut self) -> Place<'tcx> {
index 5ddae5f5300f664e5190d5ebfbf1286228274d7f..33f49ffdaf6403fd4ae06a43b763e86789ab567b 100644 (file)
@@ -85,6 +85,7 @@
 
 use crate::build::{BlockAnd, BlockAndExtension, BlockFrame, Builder, CFG};
 use rustc_data_structures::fx::FxHashMap;
+use rustc_hir::HirId;
 use rustc_index::vec::IndexVec;
 use rustc_middle::middle::region;
 use rustc_middle::mir::*;
@@ -567,25 +568,10 @@ pub(crate) fn in_scope<F, R>(
         F: FnOnce(&mut Builder<'a, 'tcx>) -> BlockAnd<R>,
     {
         let source_scope = self.source_scope;
-        let tcx = self.tcx;
         if let LintLevel::Explicit(current_hir_id) = lint_level {
-            // Use `maybe_lint_level_root_bounded` with `root_lint_level` as a bound
-            // to avoid adding Hir dependencies on our parents.
-            // We estimate the true lint roots here to avoid creating a lot of source scopes.
-
-            let parent_root = tcx.maybe_lint_level_root_bounded(
-                self.source_scopes[source_scope].local_data.as_ref().assert_crate_local().lint_root,
-                self.hir_id,
-            );
-            let current_root = tcx.maybe_lint_level_root_bounded(current_hir_id, self.hir_id);
-
-            if parent_root != current_root {
-                self.source_scope = self.new_source_scope(
-                    region_scope.1.span,
-                    LintLevel::Explicit(current_root),
-                    None,
-                );
-            }
+            let parent_id =
+                self.source_scopes[source_scope].local_data.as_ref().assert_crate_local().lint_root;
+            self.maybe_new_source_scope(region_scope.1.span, None, current_hir_id, parent_id);
         }
         self.push_scope(region_scope);
         let mut block;
@@ -758,6 +744,40 @@ fn leave_top_scope(&mut self, block: BasicBlock) -> BasicBlock {
         ))
     }
 
+    /// Possibly creates a new source scope if `current_root` and `parent_root`
+    /// are different, or if -Zmaximal-hir-to-mir-coverage is enabled.
+    pub(crate) fn maybe_new_source_scope(
+        &mut self,
+        span: Span,
+        safety: Option<Safety>,
+        current_id: HirId,
+        parent_id: HirId,
+    ) {
+        let (current_root, parent_root) =
+            if self.tcx.sess.opts.unstable_opts.maximal_hir_to_mir_coverage {
+                // Some consumers of rustc need to map MIR locations back to HIR nodes. Currently the
+                // the only part of rustc that tracks MIR -> HIR is the `SourceScopeLocalData::lint_root`
+                // field that tracks lint levels for MIR locations.  Normally the number of source scopes
+                // is limited to the set of nodes with lint annotations. The -Zmaximal-hir-to-mir-coverage
+                // flag changes this behavior to maximize the number of source scopes, increasing the
+                // granularity of the MIR->HIR mapping.
+                (current_id, parent_id)
+            } else {
+                // Use `maybe_lint_level_root_bounded` with `self.hir_id` as a bound
+                // to avoid adding Hir dependencies on our parents.
+                // We estimate the true lint roots here to avoid creating a lot of source scopes.
+                (
+                    self.tcx.maybe_lint_level_root_bounded(current_id, self.hir_id),
+                    self.tcx.maybe_lint_level_root_bounded(parent_id, self.hir_id),
+                )
+            };
+
+        if current_root != parent_root {
+            let lint_level = LintLevel::Explicit(current_root);
+            self.source_scope = self.new_source_scope(span, lint_level, safety);
+        }
+    }
+
     /// Creates a new source scope, nested in the current one.
     pub(crate) fn new_source_scope(
         &mut self,
index 5fa41ebeb6e5966f9acf748e5ea7aa3ef1588251..261b95ba95b0e36781448e9fdc7be376773f99cb 100644 (file)
@@ -704,7 +704,7 @@ fn make_mirror_unadjusted(&mut self, expr: &'tcx hir::Expr<'tcx>) -> Expr<'tcx>
             hir::ExprKind::Field(ref source, ..) => ExprKind::Field {
                 lhs: self.mirror_expr(source),
                 variant_index: VariantIdx::new(0),
-                name: Field::new(tcx.field_index(expr.hir_id, self.typeck_results)),
+                name: Field::new(self.typeck_results.field_index(expr.hir_id)),
             },
             hir::ExprKind::Cast(ref source, ref cast_ty) => {
                 // Check for a user-given type annotation on this `cast`
@@ -1079,7 +1079,7 @@ fn field_refs(&mut self, fields: &'tcx [hir::ExprField<'tcx>]) -> Box<[FieldExpr
         fields
             .iter()
             .map(|field| FieldExpr {
-                name: Field::new(self.tcx.field_index(field.hir_id, self.typeck_results)),
+                name: Field::new(self.typeck_results.field_index(field.hir_id)),
                 expr: self.mirror_expr(field.expr),
             })
             .collect()
index d60e8722cb61d5c443e20ef22d8c061d100781e0..18e9c69c4870e3b8796c5b01e1e2b73c3c6c0d18 100644 (file)
@@ -45,7 +45,7 @@
 use std::cell::Cell;
 use std::cmp::{self, max, min, Ordering};
 use std::fmt;
-use std::iter::{once, IntoIterator};
+use std::iter::once;
 use std::ops::RangeInclusive;
 
 use smallvec::{smallvec, SmallVec};
index 4c2a80e523f3537593bec024938dc2d35b246f15..48a231a6cd6b7c4648396131e1743e0a71065b04 100644 (file)
@@ -321,7 +321,7 @@ fn lower_pattern_unadjusted(&mut self, pat: &'tcx hir::Pat<'tcx>) -> Box<Pat<'tc
                 let subpatterns = fields
                     .iter()
                     .map(|field| FieldPat {
-                        field: Field::new(self.tcx.field_index(field.hir_id, self.typeck_results)),
+                        field: Field::new(self.typeck_results.field_index(field.hir_id)),
                         pattern: self.lower_pattern(&field.pat),
                     })
                     .collect();
index ce87a1916b4658034ba7941ab6149b7713375ad0..8610792c0eb5d24be0eced169c40d1d141ec3a4e 100644 (file)
@@ -596,7 +596,6 @@ fn adt_switch_block(
                 source_info: self.source_info,
                 kind: TerminatorKind::SwitchInt {
                     discr: Operand::Move(discr),
-                    switch_ty: discr_ty,
                     targets: SwitchTargets::new(
                         values.iter().copied().zip(blocks.iter().copied()),
                         *blocks.last().unwrap(),
@@ -716,7 +715,7 @@ fn drop_loop(
             is_cleanup: unwind.is_cleanup(),
             terminator: Some(Terminator {
                 source_info: self.source_info,
-                kind: TerminatorKind::if_(tcx, move_(can_go), succ, drop_block),
+                kind: TerminatorKind::if_(move_(can_go), succ, drop_block),
             }),
         };
         let loop_block = self.elaborator.patch().new_block(loop_block);
@@ -781,7 +780,6 @@ fn open_drop_for_array(&mut self, ety: Ty<'tcx>, opt_size: Option<u64>) -> Basic
                 source_info: self.source_info,
                 kind: TerminatorKind::SwitchInt {
                     discr: move_(elem_size),
-                    switch_ty: tcx.types.usize,
                     targets: SwitchTargets::static_if(
                         0,
                         self.drop_loop_pair(ety, false, len),
@@ -1021,7 +1019,7 @@ fn drop_flag_test_block(
             DropStyle::Static => on_set,
             DropStyle::Conditional | DropStyle::Open => {
                 let flag = self.elaborator.get_drop_flag(self.path).unwrap();
-                let term = TerminatorKind::if_(self.tcx(), flag, on_set, on_unset);
+                let term = TerminatorKind::if_(flag, on_set, on_unset);
                 self.new_block(unwind, term)
             }
         }
index 5c77f3ea395334abc0d5f0c891b11a606ae1bcc1..5ff6b9e7e69b4f8257a49d4190a996da6b75e017 100644 (file)
@@ -261,7 +261,7 @@ fn join_state_into_successors_of<'tcx, A>(
                     propagate(pred, &tmp);
                 }
 
-                mir::TerminatorKind::SwitchInt { targets: _, ref discr, switch_ty: _ } => {
+                mir::TerminatorKind::SwitchInt { targets: _, ref discr } => {
                     let mut applier = BackwardSwitchIntEdgeEffectsApplier {
                         body,
                         pred,
@@ -577,7 +577,7 @@ fn join_state_into_successors_of<'tcx, A>(
                 }
             }
 
-            SwitchInt { ref targets, ref discr, switch_ty: _ } => {
+            SwitchInt { ref targets, ref discr } => {
                 let mut applier = ForwardSwitchIntEdgeEffectsApplier {
                     exit_state,
                     targets,
index bc75645e7c9579abc12b8df22ced1a0aa73f7861..6ddbe69e17e75fae367d832918ccaefd9bfecfd1 100644 (file)
@@ -294,14 +294,7 @@ fn write_graphviz_results<'tcx, A>(
         None if tcx.sess.opts.unstable_opts.dump_mir_dataflow
             && dump_enabled(tcx, A::NAME, def_id) =>
         {
-            create_dump_file(
-                tcx,
-                ".dot",
-                None,
-                A::NAME,
-                &pass_name.unwrap_or("-----"),
-                body.source,
-            )?
+            create_dump_file(tcx, ".dot", false, A::NAME, &pass_name.unwrap_or("-----"), body)?
         }
 
         _ => return Ok(()),
index f0e75c53ea15c93e9fa6c7fcd46843c25a191f26..8fdac7b2cf501e1540a526392a1cde97c7397216 100644 (file)
@@ -26,7 +26,7 @@
 //! ## `PartialOrd`
 //!
 //! Given that they represent partially ordered sets, you may be surprised that [`JoinSemiLattice`]
-//! and [`MeetSemiLattice`] do not have [`PartialOrd`][std::cmp::PartialOrd] as a supertrait. This
+//! and [`MeetSemiLattice`] do not have [`PartialOrd`] as a supertrait. This
 //! is because most standard library types use lexicographic ordering instead of set inclusion for
 //! their `PartialOrd` impl. Since we do not actually need to compare lattice elements to run a
 //! dataflow analysis, there's no need for a newtype wrapper with a custom `PartialOrd` impl. The
index cc69a1bb02db19cac318ec2c149bd18d7dcfc9bf..7df0114226418c890378eea776e08cc4b6b82973 100644 (file)
@@ -406,7 +406,7 @@ fn clone_from(&mut self, source: &Self) {
 /// The dataflow state for an instance of [`ValueAnalysis`].
 ///
 /// Every instance specifies a lattice that represents the possible values of a single tracked
-/// place. If we call this lattice `V` and set set of tracked places `P`, then a [`State`] is an
+/// place. If we call this lattice `V` and set of tracked places `P`, then a [`State`] is an
 /// element of `{unreachable} âˆª (P -> V)`. This again forms a lattice, where the bottom element is
 /// `unreachable` and the top element is the mapping `p â†¦ âŠ¤`. Note that the mapping `p â†¦ âŠ¥` is not
 /// the bottom element (because joining an unreachable and any other reachable state yields a
index 036b5589849a274542145f19e7876cc252fd6cf1..3d22035f0785ed57509c86c251355156d92d3665 100644 (file)
 
 pub struct AddRetag;
 
-/// Determines whether this place is "stable": Whether, if we evaluate it again
-/// after the assignment, we can be sure to obtain the same place value.
-/// (Concurrent accesses by other threads are no problem as these are anyway non-atomic
-/// copies.  Data races are UB.)
-fn is_stable(place: PlaceRef<'_>) -> bool {
-    // Which place this evaluates to can change with any memory write,
-    // so cannot assume deref to be stable.
-    !place.has_deref()
-}
-
 /// Determine whether this type may contain a reference (or box), and thus needs retagging.
 /// We will only recurse `depth` times into Tuples/ADTs to bound the cost of this.
 fn may_contain_reference<'tcx>(ty: Ty<'tcx>, depth: u32, tcx: TyCtxt<'tcx>) -> bool {
@@ -69,22 +59,10 @@ fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
         let basic_blocks = body.basic_blocks.as_mut();
         let local_decls = &body.local_decls;
         let needs_retag = |place: &Place<'tcx>| {
-            // FIXME: Instead of giving up for unstable places, we should introduce
-            // a temporary and retag on that.
-            is_stable(place.as_ref())
+            !place.has_deref() // we're not eally interested in stores to "outside" locations, they are hard to keep track of anyway
                 && may_contain_reference(place.ty(&*local_decls, tcx).ty, /*depth*/ 3, tcx)
                 && !local_decls[place.local].is_deref_temp()
         };
-        let place_base_raw = |place: &Place<'tcx>| {
-            // If this is a `Deref`, get the type of what we are deref'ing.
-            if place.has_deref() {
-                let ty = &local_decls[place.local].ty;
-                ty.is_unsafe_ptr()
-            } else {
-                // Not a deref, and thus not raw.
-                false
-            }
-        };
 
         // PART 1
         // Retag arguments at the beginning of the start block.
@@ -108,7 +86,7 @@ fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
         }
 
         // PART 2
-        // Retag return values of functions.  Also escape-to-raw the argument of `drop`.
+        // Retag return values of functions.
         // We collect the return destinations because we cannot mutate while iterating.
         let returns = basic_blocks
             .iter_mut()
@@ -140,30 +118,25 @@ fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
         }
 
         // PART 3
-        // Add retag after assignment.
+        // Add retag after assignments where data "enters" this function: the RHS is behind a deref and the LHS is not.
         for block_data in basic_blocks {
             // We want to insert statements as we iterate.  To this end, we
             // iterate backwards using indices.
             for i in (0..block_data.statements.len()).rev() {
                 let (retag_kind, place) = match block_data.statements[i].kind {
-                    // Retag-as-raw after escaping to a raw pointer, if the referent
-                    // is not already a raw pointer.
-                    StatementKind::Assign(box (lplace, Rvalue::AddressOf(_, ref rplace)))
-                        if !place_base_raw(rplace) =>
-                    {
-                        (RetagKind::Raw, lplace)
-                    }
                     // Retag after assignments of reference type.
                     StatementKind::Assign(box (ref place, ref rvalue)) if needs_retag(place) => {
-                        let kind = match rvalue {
-                            Rvalue::Ref(_, borrow_kind, _)
-                                if borrow_kind.allows_two_phase_borrow() =>
-                            {
-                                RetagKind::TwoPhase
-                            }
-                            _ => RetagKind::Default,
+                        let add_retag = match rvalue {
+                            // Ptr-creating operations already do their own internal retagging, no
+                            // need to also add a retag statement.
+                            Rvalue::Ref(..) | Rvalue::AddressOf(..) => false,
+                            _ => true,
                         };
-                        (kind, *place)
+                        if add_retag {
+                            (RetagKind::Default, *place)
+                        } else {
+                            continue;
+                        }
                     }
                     // Do nothing for the rest
                     _ => continue,
index 0a305a402095d758aecbe4ca5287f357f3c1a61e..40eefda4f076326002a270044b1526f9988110c3 100644 (file)
@@ -82,8 +82,9 @@ fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location
                 }
 
                 let target_bb_terminator = target_bb.terminator();
-                let (discr, switch_ty, targets) = target_bb_terminator.kind.as_switch()?;
+                let (discr, targets) = target_bb_terminator.kind.as_switch()?;
                 if discr.place() == Some(*place) {
+                    let switch_ty = place.ty(self.body.local_decls(), self.tcx).ty;
                     // We now know that the Switch matches on the const place, and it is statementless
                     // Now find which value in the Switch matches the const value.
                     let const_value =
index 0f8679b0bd69dd0f797e684aa3cb3a9584907f63..d6a298fade42e889e5b4521693a3f54bb47f2805 100644 (file)
@@ -638,7 +638,7 @@ pub(super) fn dump_coverage_spanview<'tcx>(
     let def_id = mir_source.def_id();
 
     let span_viewables = span_viewables(tcx, mir_body, basic_coverage_blocks, &coverage_spans);
-    let mut file = create_dump_file(tcx, "html", None, pass_name, &0, mir_source)
+    let mut file = create_dump_file(tcx, "html", false, pass_name, &0, mir_body)
         .expect("Unexpected error creating MIR spanview HTML file");
     let crate_name = tcx.crate_name(def_id.krate);
     let item_name = tcx.def_path(def_id).to_filename_friendly_no_crate();
@@ -739,7 +739,7 @@ pub(super) fn dump_coverage_graphviz<'tcx>(
                 .join("\n  ")
         ));
     }
-    let mut file = create_dump_file(tcx, "dot", None, pass_name, &0, mir_source)
+    let mut file = create_dump_file(tcx, "dot", false, pass_name, &0, mir_body)
         .expect("Unexpected error creating BasicCoverageBlock graphviz DOT file");
     graphviz_writer
         .write_graphviz(tcx, &mut file)
index 9c9ed5fa5105eda71866b54d8dd8b24f99abcda3..eba6a2b34e47ddb11379dc589c7090db1611b18d 100644 (file)
@@ -37,7 +37,7 @@
 use rustc_index::vec::{Idx, IndexVec};
 use rustc_middle::mir::coverage::CoverageKind;
 use rustc_middle::mir::*;
-use rustc_middle::ty::{self, Ty, TyCtxt};
+use rustc_middle::ty;
 use rustc_span::{self, BytePos, Pos, Span, DUMMY_SP};
 
 // All `TEMP_BLOCK` targets should be replaced before calling `to_body() -> mir::Body`.
@@ -47,7 +47,6 @@ struct MockBlocks<'tcx> {
     blocks: IndexVec<BasicBlock, BasicBlockData<'tcx>>,
     dummy_place: Place<'tcx>,
     next_local: usize,
-    bool_ty: Ty<'tcx>,
 }
 
 impl<'tcx> MockBlocks<'tcx> {
@@ -56,7 +55,6 @@ fn new() -> Self {
             blocks: IndexVec::new(),
             dummy_place: Place { local: RETURN_PLACE, projection: ty::List::empty() },
             next_local: 0,
-            bool_ty: TyCtxt::BOOL_TY_FOR_UNIT_TESTING,
         }
     }
 
@@ -157,7 +155,6 @@ fn goto(&mut self, some_from_block: Option<BasicBlock>) -> BasicBlock {
     fn switchint(&mut self, some_from_block: Option<BasicBlock>) -> BasicBlock {
         let switchint_kind = TerminatorKind::SwitchInt {
             discr: Operand::Move(Place::from(self.new_temp())),
-            switch_ty: self.bool_ty, // just a dummy value
             targets: SwitchTargets::static_if(0, TEMP_BLOCK, TEMP_BLOCK),
         };
         self.add_block_from(some_from_block, switchint_kind)
index 8cd44ab82ccc4cb35d392840d90ee7b8a24cf2d6..97485c4f57b12ea872de807daf68c6ca9fe7ec8a 100644 (file)
@@ -787,7 +787,7 @@ fn dest_prop_mir_dump<'body, 'tcx>(
     round: usize,
 ) {
     let mut reachable = None;
-    dump_mir(tcx, None, "DestinationPropagation-dataflow", &round, body, |pass_where, w| {
+    dump_mir(tcx, false, "DestinationPropagation-dataflow", &round, body, |pass_where, w| {
         let reachable = reachable.get_or_insert_with(|| traversal::reachable_as_bitset(body));
 
         match pass_where {
index 6b995141a2bef7602ea8cfb6b7c9038bdad1cd21..594cbd8977ebbf55dca5294946ce15eecde9076e 100644 (file)
@@ -1,6 +1,5 @@
 //! This pass just dumps MIR at a specified point.
 
-use std::borrow::Cow;
 use std::fs::File;
 use std::io;
 
@@ -8,20 +7,20 @@
 use rustc_middle::mir::write_mir_pretty;
 use rustc_middle::mir::Body;
 use rustc_middle::ty::TyCtxt;
-use rustc_session::config::{OutputFilenames, OutputType};
+use rustc_session::config::OutputType;
 
 pub struct Marker(pub &'static str);
 
 impl<'tcx> MirPass<'tcx> for Marker {
-    fn name(&self) -> Cow<'_, str> {
-        Cow::Borrowed(self.0)
+    fn name(&self) -> &str {
+        self.0
     }
 
     fn run_pass(&self, _tcx: TyCtxt<'tcx>, _body: &mut Body<'tcx>) {}
 }
 
-pub fn emit_mir(tcx: TyCtxt<'_>, outputs: &OutputFilenames) -> io::Result<()> {
-    let path = outputs.path(OutputType::Mir);
+pub fn emit_mir(tcx: TyCtxt<'_>) -> io::Result<()> {
+    let path = tcx.output_filenames(()).path(OutputType::Mir);
     let mut f = io::BufWriter::new(File::create(&path)?);
     write_mir_pretty(tcx, None, &mut f)?;
     Ok(())
index 32e738bbcea44b108c47e2dd948cef4f242dbbdb..8a7b027ddda7eb91316f612be8995748d6729fdf 100644 (file)
@@ -121,7 +121,6 @@ fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
 
             let TerminatorKind::SwitchInt {
                 discr: parent_op,
-                switch_ty: parent_ty,
                 targets: parent_targets
             } = &bbs[parent].terminator().kind else {
                 unreachable!()
@@ -132,6 +131,7 @@ fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
                 Operand::Copy(x) => Operand::Copy(*x),
                 Operand::Constant(x) => Operand::Constant(x.clone()),
             };
+            let parent_ty = parent_op.ty(body.local_decls(), tcx);
             let statements_before = bbs[parent].statements.len();
             let parent_end = Location { block: parent, statement_index: statements_before };
 
@@ -153,7 +153,7 @@ fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
             // create temp to store inequality comparison between the two discriminants, `_t` in
             // example above
             let nequal = BinOp::Ne;
-            let comp_res_type = nequal.ty(tcx, *parent_ty, opt_data.child_ty);
+            let comp_res_type = nequal.ty(tcx, parent_ty, opt_data.child_ty);
             let comp_temp = patch.new_temp(comp_res_type, opt_data.child_source.span);
             patch.add_statement(parent_end, StatementKind::StorageLive(comp_temp));
 
@@ -181,7 +181,6 @@ fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
                 kind: TerminatorKind::SwitchInt {
                     // switch on the first discriminant, so we can mark the second one as dead
                     discr: parent_op,
-                    switch_ty: opt_data.child_ty,
                     targets: eq_targets,
                 },
             }));
@@ -193,12 +192,7 @@ fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
             let false_case = eq_bb;
             patch.patch_terminator(
                 parent,
-                TerminatorKind::if_(
-                    tcx,
-                    Operand::Move(Place::from(comp_temp)),
-                    true_case,
-                    false_case,
-                ),
+                TerminatorKind::if_(Operand::Move(Place::from(comp_temp)), true_case, false_case),
             );
 
             // generate StorageDead for the second_discriminant_temp not in use anymore
@@ -319,11 +313,11 @@ fn evaluate_candidate<'tcx>(
     let bbs = &body.basic_blocks;
     let TerminatorKind::SwitchInt {
         targets,
-        switch_ty: parent_ty,
-        ..
+        discr: parent_discr,
     } = &bbs[parent].terminator().kind else {
         return None
     };
+    let parent_ty = parent_discr.ty(body.local_decls(), tcx);
     let parent_dest = {
         let poss = targets.otherwise();
         // If the fallthrough on the parent is trivially unreachable, we can let the
@@ -339,12 +333,12 @@ fn evaluate_candidate<'tcx>(
     let (_, child) = targets.iter().next()?;
     let child_terminator = &bbs[child].terminator();
     let TerminatorKind::SwitchInt {
-        switch_ty: child_ty,
         targets: child_targets,
-        ..
+        discr: child_discr,
     } = &child_terminator.kind else {
         return None
     };
+    let child_ty = child_discr.ty(body.local_decls(), tcx);
     if child_ty != parent_ty {
         return None;
     }
@@ -372,7 +366,7 @@ fn evaluate_candidate<'tcx>(
     Some(OptimizationData {
         destination,
         child_place: *child_place,
-        child_ty: *child_ty,
+        child_ty,
         child_source: child_terminator.source_info,
     })
 }
index ffe4d43bc88e88970ddf6d36aa24ccda53f7f4f6..c08593afe9d88ff900b6c116ffcd8183cc0b89d4 100644 (file)
@@ -877,11 +877,7 @@ fn insert_switch<'tcx>(
     let (assign, discr) = transform.get_discr(body);
     let switch_targets =
         SwitchTargets::new(cases.iter().map(|(i, bb)| ((*i) as u128, *bb)), default_block);
-    let switch = TerminatorKind::SwitchInt {
-        discr: Operand::Move(discr),
-        switch_ty: transform.discr_ty,
-        targets: switch_targets,
-    };
+    let switch = TerminatorKind::SwitchInt { discr: Operand::Move(discr), targets: switch_targets };
 
     let source_info = SourceInfo::outermost(body.span);
     body.basic_blocks_mut().raw.insert(
@@ -985,22 +981,12 @@ fn create_generator_drop_shim<'tcx>(
         tcx.mk_ptr(ty::TypeAndMut { ty: gen_ty, mutbl: hir::Mutability::Mut }),
         source_info,
     );
-    if tcx.sess.opts.unstable_opts.mir_emit_retag {
-        // Alias tracking must know we changed the type
-        body.basic_blocks_mut()[START_BLOCK].statements.insert(
-            0,
-            Statement {
-                source_info,
-                kind: StatementKind::Retag(RetagKind::Raw, Box::new(Place::from(SELF_ARG))),
-            },
-        )
-    }
 
     // Make sure we remove dead blocks to remove
     // unrelated code from the resume part of the function
     simplify::remove_dead_blocks(tcx, &mut body);
 
-    dump_mir(tcx, None, "generator_drop", &0, &body, |_, _| Ok(()));
+    dump_mir(tcx, false, "generator_drop", &0, &body, |_, _| Ok(()));
 
     body
 }
@@ -1171,7 +1157,7 @@ fn create_generator_resume_function<'tcx>(
     // unrelated code from the drop part of the function
     simplify::remove_dead_blocks(tcx, body);
 
-    dump_mir(tcx, None, "generator_resume", &0, body, |_, _| Ok(()));
+    dump_mir(tcx, false, "generator_resume", &0, body, |_, _| Ok(()));
 }
 
 fn insert_clean_drop(body: &mut Body<'_>) -> BasicBlock {
@@ -1394,14 +1380,14 @@ fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
         // This is expanded to a drop ladder in `elaborate_generator_drops`.
         let drop_clean = insert_clean_drop(body);
 
-        dump_mir(tcx, None, "generator_pre-elab", &0, body, |_, _| Ok(()));
+        dump_mir(tcx, false, "generator_pre-elab", &0, body, |_, _| Ok(()));
 
         // Expand `drop(generator_struct)` to a drop ladder which destroys upvars.
         // If any upvars are moved out of, drop elaboration will handle upvar destruction.
         // However we need to also elaborate the code generated by `insert_clean_drop`.
         elaborate_generator_drops(tcx, body);
 
-        dump_mir(tcx, None, "generator_post-transform", &0, body, |_, _| Ok(()));
+        dump_mir(tcx, false, "generator_post-transform", &0, body, |_, _| Ok(()));
 
         // Create a copy of our MIR and use it to create the drop shim for the generator
         let drop_shim = create_generator_drop_shim(tcx, &transform, gen_ty, body, drop_clean);
index 9174f04887e4229aa9f7596b7c101df5298148d8..220cf7df9c6c7e99cd35d103fa959988f9b1db34 100644 (file)
@@ -8,7 +8,6 @@
 use rustc_middle::mir::*;
 use rustc_middle::ty::{self, Instance, InstanceDef, ParamEnv, Ty, TyCtxt};
 use rustc_session::config::OptLevel;
-use rustc_span::def_id::DefId;
 use rustc_span::{hygiene::ExpnKind, ExpnData, LocalExpnId, Span};
 use rustc_target::abi::VariantIdx;
 use rustc_target::spec::abi::Abi;
@@ -87,13 +86,8 @@ fn inline<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) -> bool {
 
     let param_env = tcx.param_env_reveal_all_normalized(def_id);
 
-    let mut this = Inliner {
-        tcx,
-        param_env,
-        codegen_fn_attrs: tcx.codegen_fn_attrs(def_id),
-        history: Vec::new(),
-        changed: false,
-    };
+    let mut this =
+        Inliner { tcx, param_env, codegen_fn_attrs: tcx.codegen_fn_attrs(def_id), changed: false };
     let blocks = BasicBlock::new(0)..body.basic_blocks.next_index();
     this.process_blocks(body, blocks);
     this.changed
@@ -104,12 +98,6 @@ struct Inliner<'tcx> {
     param_env: ParamEnv<'tcx>,
     /// Caller codegen attributes.
     codegen_fn_attrs: &'tcx CodegenFnAttrs,
-    /// Stack of inlined instances.
-    /// We only check the `DefId` and not the substs because we want to
-    /// avoid inlining cases of polymorphic recursion.
-    /// The number of `DefId`s is finite, so checking history is enough
-    /// to ensure that we do not loop endlessly while inlining.
-    history: Vec<DefId>,
     /// Indicates that the caller body has been modified.
     changed: bool,
 }
@@ -134,12 +122,12 @@ fn process_blocks(&mut self, caller_body: &mut Body<'tcx>, blocks: Range<BasicBl
                     debug!("not-inlined {} [{}]", callsite.callee, reason);
                     continue;
                 }
-                Ok(new_blocks) => {
+                Ok(_) => {
                     debug!("inlined {}", callsite.callee);
                     self.changed = true;
-                    self.history.push(callsite.callee.def_id());
-                    self.process_blocks(caller_body, new_blocks);
-                    self.history.pop();
+                    // We could process the blocks returned by `try_inlining` here. However, that
+                    // leads to exponential compile times due to the top-down nature of this kind
+                    // of inlining.
                 }
             }
         }
@@ -313,10 +301,6 @@ fn resolve_callsite(
                     return None;
                 }
 
-                if self.history.contains(&callee.def_id()) {
-                    return None;
-                }
-
                 let fn_sig = self.tcx.bound_fn_sig(def_id).subst(self.tcx, substs);
 
                 return Some(CallSite {
@@ -363,10 +347,6 @@ fn check_codegen_attributes(
             return Err("C variadic");
         }
 
-        if callee_attrs.flags.contains(CodegenFnAttrFlags::NAKED) {
-            return Err("naked");
-        }
-
         if callee_attrs.flags.contains(CodegenFnAttrFlags::COLD) {
             return Err("cold");
         }
index a0ba69c89b048491f9840a9cd6806f91bf2fd46f..ce05db5b762ac9a48d3b2d15f6b3be72a3a5d526 100644 (file)
@@ -55,10 +55,9 @@ fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
                 continue;
             }
 
-            let (discr, val, switch_ty, first, second) = match bbs[bb_idx].terminator().kind {
+            let (discr, val, first, second) = match bbs[bb_idx].terminator().kind {
                 TerminatorKind::SwitchInt {
                     discr: ref discr @ (Operand::Copy(_) | Operand::Move(_)),
-                    switch_ty,
                     ref targets,
                     ..
                 } if targets.iter().len() == 1 => {
@@ -66,7 +65,7 @@ fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
                     if target == targets.otherwise() {
                         continue;
                     }
-                    (discr, value, switch_ty, target, targets.otherwise())
+                    (discr, value, target, targets.otherwise())
                 }
                 // Only optimize switch int statements
                 _ => continue,
@@ -105,10 +104,11 @@ fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
             }
             // Take ownership of items now that we know we can optimize.
             let discr = discr.clone();
+            let discr_ty = discr.ty(&body.local_decls, tcx);
 
             // Introduce a temporary for the discriminant value.
             let source_info = bbs[bb_idx].terminator().source_info;
-            let discr_local = body.local_decls.push(LocalDecl::new(switch_ty, source_info.span));
+            let discr_local = body.local_decls.push(LocalDecl::new(discr_ty, source_info.span));
 
             // We already checked that first and second are different blocks,
             // and bb_idx has a different terminator from both of them.
@@ -130,10 +130,10 @@ fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
                             (*f).clone()
                         } else {
                             // Different value between blocks. Make value conditional on switch condition.
-                            let size = tcx.layout_of(param_env.and(switch_ty)).unwrap().size;
+                            let size = tcx.layout_of(param_env.and(discr_ty)).unwrap().size;
                             let const_cmp = Operand::const_from_scalar(
                                 tcx,
-                                switch_ty,
+                                discr_ty,
                                 rustc_const_eval::interpret::Scalar::from_uint(val, size),
                                 rustc_span::DUMMY_SP,
                             );
index 27dbc3e22c97a58ac53b09eec34d355229906ce3..e1b65823a5a9c86669ba43af79a11e1ccdb9464c 100644 (file)
@@ -1,5 +1,3 @@
-use std::borrow::Cow;
-
 use rustc_middle::mir::{self, Body, MirPhase, RuntimePhase};
 use rustc_middle::ty::TyCtxt;
 use rustc_session::Session;
@@ -8,13 +6,9 @@
 
 /// Just like `MirPass`, except it cannot mutate `Body`.
 pub trait MirLint<'tcx> {
-    fn name(&self) -> Cow<'_, str> {
+    fn name(&self) -> &str {
         let name = std::any::type_name::<Self>();
-        if let Some(tail) = name.rfind(':') {
-            Cow::from(&name[tail + 1..])
-        } else {
-            Cow::from(name)
-        }
+        if let Some((_, tail)) = name.rsplit_once(':') { tail } else { name }
     }
 
     fn is_enabled(&self, _sess: &Session) -> bool {
@@ -32,7 +26,7 @@ impl<'tcx, T> MirPass<'tcx> for Lint<T>
 where
     T: MirLint<'tcx>,
 {
-    fn name(&self) -> Cow<'_, str> {
+    fn name(&self) -> &str {
         self.0.name()
     }
 
@@ -55,7 +49,7 @@ impl<'tcx, T> MirPass<'tcx> for WithMinOptLevel<T>
 where
     T: MirPass<'tcx>,
 {
-    fn name(&self) -> Cow<'_, str> {
+    fn name(&self) -> &str {
         self.1.name()
     }
 
@@ -146,10 +140,11 @@ fn run_passes_inner<'tcx>(
         }
 
         body.phase = new_phase;
+        body.pass_count = 0;
 
         dump_mir_for_phase_change(tcx, body);
         if validate || new_phase == MirPhase::Runtime(RuntimePhase::Optimized) {
-            validate_body(tcx, body, format!("after phase change to {}", new_phase));
+            validate_body(tcx, body, format!("after phase change to {}", new_phase.name()));
         }
 
         body.pass_count = 1;
@@ -166,11 +161,9 @@ pub fn dump_mir_for_pass<'tcx>(
     pass_name: &str,
     is_after: bool,
 ) {
-    let phase_index = body.phase.phase_index();
-
     mir::dump_mir(
         tcx,
-        Some(&format_args!("{:03}-{:03}", phase_index, body.pass_count)),
+        true,
         pass_name,
         if is_after { &"after" } else { &"before" },
         body,
@@ -179,14 +172,6 @@ pub fn dump_mir_for_pass<'tcx>(
 }
 
 pub fn dump_mir_for_phase_change<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>) {
-    let phase_index = body.phase.phase_index();
-
-    mir::dump_mir(
-        tcx,
-        Some(&format_args!("{:03}-000", phase_index)),
-        &format!("{}", body.phase),
-        &"after",
-        body,
-        |_, _| Ok(()),
-    )
+    assert_eq!(body.pass_count, 0);
+    mir::dump_mir(tcx, true, body.phase.name(), &"after", body, |_, _| Ok(()))
 }
index 40be4f146db98ffefec45920ffeca6e460609786..569e783fee847b17a561293e001783627773ab9e 100644 (file)
@@ -1,8 +1,7 @@
 //! Removes assignments to ZST places.
 
 use crate::MirPass;
-use rustc_middle::mir::tcx::PlaceTy;
-use rustc_middle::mir::{Body, LocalDecls, Place, StatementKind};
+use rustc_middle::mir::{Body, StatementKind};
 use rustc_middle::ty::{self, Ty, TyCtxt};
 
 pub struct RemoveZsts;
@@ -35,9 +34,6 @@ fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
                     if !layout.is_zst() {
                         continue;
                     }
-                    if involves_a_union(place, local_decls, tcx) {
-                        continue;
-                    }
                     if tcx.consider_optimizing(|| {
                         format!(
                             "RemoveZsts - Place: {:?} SourceInfo: {:?}",
@@ -63,24 +59,3 @@ fn maybe_zst(ty: Ty<'_>) -> bool {
         _ => false,
     }
 }
-
-/// Miri lazily allocates memory for locals on assignment,
-/// so we must preserve writes to unions and union fields,
-/// or it will ICE on reads of those fields.
-fn involves_a_union<'tcx>(
-    place: Place<'tcx>,
-    local_decls: &LocalDecls<'tcx>,
-    tcx: TyCtxt<'tcx>,
-) -> bool {
-    let mut place_ty = PlaceTy::from_ty(local_decls[place.local].ty);
-    if place_ty.ty.is_union() {
-        return true;
-    }
-    for elem in place.projection {
-        place_ty = place_ty.projection_ty(tcx, elem);
-        if place_ty.ty.is_union() {
-            return true;
-        }
-    }
-    return false;
-}
index a115bb2831a4b2c1c1ec7dc04d4015495200a30e..f92a0e826dcdfb6dcf55e264235d07e360a5137f 100644 (file)
@@ -177,16 +177,6 @@ fn build_drop_shim<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, ty: Option<Ty<'tcx>>)
     if ty.is_some() {
         // The first argument (index 0), but add 1 for the return value.
         let dropee_ptr = Place::from(Local::new(1 + 0));
-        if tcx.sess.opts.unstable_opts.mir_emit_retag {
-            // Function arguments should be retagged, and we make this one raw.
-            body.basic_blocks_mut()[START_BLOCK].statements.insert(
-                0,
-                Statement {
-                    source_info,
-                    kind: StatementKind::Retag(RetagKind::Raw, Box::new(dropee_ptr)),
-                },
-            );
-        }
         let patch = {
             let param_env = tcx.param_env_reveal_all_normalized(def_id);
             let mut elaborator =
@@ -558,7 +548,6 @@ fn generator_shim(
                 statements.push(statement);
                 *kind = TerminatorKind::SwitchInt {
                     discr: Operand::Move(temp),
-                    switch_ty: discr_ty,
                     targets: SwitchTargets::new(cases.into_iter(), unreachable),
                 };
             }
index 57d372fda5697f508c9a799d06f8cac051f18af9..8212a7b523bbc98d5d1e4d8d76e57864432d61df 100644 (file)
@@ -35,8 +35,6 @@
 use rustc_middle::mir::*;
 use rustc_middle::ty::TyCtxt;
 use smallvec::SmallVec;
-use std::borrow::Cow;
-use std::convert::TryInto;
 
 pub struct SimplifyCfg {
     label: String,
@@ -57,8 +55,8 @@ pub fn simplify_cfg<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
 }
 
 impl<'tcx> MirPass<'tcx> for SimplifyCfg {
-    fn name(&self) -> Cow<'_, str> {
-        Cow::Borrowed(&self.label)
+    fn name(&self) -> &str {
+        &self.label
     }
 
     fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
index 3bbae5b8976ccde862a084291b64948a56de8315..8164b3052786aa1ea07d979f6607ca8988f6b9ef 100644 (file)
@@ -2,8 +2,6 @@
 use rustc_middle::mir::*;
 use rustc_middle::ty::TyCtxt;
 
-use std::borrow::Cow;
-
 /// A pass that replaces a branch with a goto when its condition is known.
 pub struct SimplifyConstCondition {
     label: String,
@@ -16,8 +14,8 @@ pub fn new(label: &str) -> Self {
 }
 
 impl<'tcx> MirPass<'tcx> for SimplifyConstCondition {
-    fn name(&self) -> Cow<'_, str> {
-        Cow::Borrowed(&self.label)
+    fn name(&self) -> &str {
+        &self.label
     }
 
     fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
@@ -26,12 +24,9 @@ fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
             let terminator = block.terminator_mut();
             terminator.kind = match terminator.kind {
                 TerminatorKind::SwitchInt {
-                    discr: Operand::Constant(ref c),
-                    switch_ty,
-                    ref targets,
-                    ..
+                    discr: Operand::Constant(ref c), ref targets, ..
                 } => {
-                    let constant = c.literal.try_eval_bits(tcx, param_env, switch_ty);
+                    let constant = c.literal.try_eval_bits(tcx, param_env, c.ty());
                     if let Some(constant) = constant {
                         let target = targets.target_for_value(constant);
                         TerminatorKind::Goto { target }
index 321d8c63b6e028c3d7c9b68d5dd0991c1db4879d..dcad1518eb63eb0d853037b109b9b7d800b727c8 100644 (file)
@@ -127,11 +127,8 @@ fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
             let targets = SwitchTargets::new(iter::once((new_value, bb_cond)), bb_otherwise);
 
             let terminator = bb.terminator_mut();
-            terminator.kind = TerminatorKind::SwitchInt {
-                discr: Operand::Move(opt.to_switch_on),
-                switch_ty: opt.branch_value_ty,
-                targets,
-            };
+            terminator.kind =
+                TerminatorKind::SwitchInt { discr: Operand::Move(opt.to_switch_on), targets };
         }
 
         for (idx, bb_idx) in storage_deads_to_remove {
index 95fda2eafe8a1799df333461355abe2eb2fc770f..06deca2fffb4889cc447878136b545a0243de852 100644 (file)
@@ -76,7 +76,7 @@ fn remove_successors<'tcx, F>(
     let terminator = match terminator_kind {
         // This will unconditionally run into an unreachable and is therefore unreachable as well.
         TerminatorKind::Goto { target } if is_unreachable(*target) => TerminatorKind::Unreachable,
-        TerminatorKind::SwitchInt { targets, discr, switch_ty } => {
+        TerminatorKind::SwitchInt { targets, discr } => {
             let otherwise = targets.otherwise();
 
             // If all targets are unreachable, we can be unreachable as well.
@@ -110,11 +110,7 @@ fn remove_successors<'tcx, F>(
                     return None;
                 }
 
-                TerminatorKind::SwitchInt {
-                    discr: discr.clone(),
-                    switch_ty: *switch_ty,
-                    targets: new_targets,
-                }
+                TerminatorKind::SwitchInt { discr: discr.clone(), targets: new_targets }
             } else {
                 // If the otherwise branch is reachable, we don't want to delete any unreachable branches.
                 return None;
index 650076c2213a35f1231e6c1bbb72b01f5ed902df..703ed09a254a96899d2019a1d29afba864a4bb97 100644 (file)
@@ -20,7 +20,6 @@
     Const, Ty, TyCtxt,
 };
 use rustc_span::symbol::sym;
-use std::convert::TryInto;
 use std::ops::ControlFlow;
 
 use crate::errors::UnusedGenericParams;
index c7d239b647f35b2bc273fdc0185a5cf224f13ac9..686454a8f18117f1323fa6dcea384719770e604f 100644 (file)
@@ -6,7 +6,6 @@
 use rustc_ast::token::{self, Delimiter, Nonterminal};
 use rustc_errors::{error_code, fluent, Diagnostic, IntoDiagnostic, PResult};
 use rustc_span::{sym, BytePos, Span};
-use std::convert::TryInto;
 
 // Public for rustfmt usage
 #[derive(Debug)]
index a084a7010885927344a3e24e834cd27e03e00fcb..b97f22417cb7bdcc82482abf2a6314d4ff664c03 100644 (file)
@@ -8,7 +8,6 @@
 use rustc_session::parse::ParseSess;
 use rustc_span::{sym, Span, DUMMY_SP};
 
-use std::convert::TryInto;
 use std::ops::Range;
 
 /// A wrapper type to ensure that the parser handles outer attributes correctly.
index 07f03e0d582cbb17d26cecdc69493fc56e01070d..8a3545eb3be3ab5d874b9c11acc48761774706f1 100644 (file)
@@ -390,20 +390,11 @@ fn should_continue_as_assoc_expr(&mut self, lhs: &Expr) -> bool {
             // want to keep their span info to improve diagnostics in these cases in a later stage.
             (true, Some(AssocOp::Multiply)) | // `{ 42 } *foo = bar;` or `{ 42 } * 3`
             (true, Some(AssocOp::Subtract)) | // `{ 42 } -5`
-            (true, Some(AssocOp::Add)) // `{ 42 } + 42
-            // If the next token is a keyword, then the tokens above *are* unambiguously incorrect:
-            // `if x { a } else { b } && if y { c } else { d }`
-            if !self.look_ahead(1, |t| t.is_used_keyword()) => {
-                // These cases are ambiguous and can't be identified in the parser alone.
-                let sp = self.sess.source_map().start_point(self.token.span);
-                self.sess.ambiguous_block_expr_parse.borrow_mut().insert(sp, lhs.span);
-                false
-            }
-            (true, Some(AssocOp::LAnd)) |
-            (true, Some(AssocOp::LOr)) |
-            (true, Some(AssocOp::BitOr)) => {
-                // `{ 42 } &&x` (#61475) or `{ 42 } && if x { 1 } else { 0 }`. Separated from the
-                // above due to #74233.
+            (true, Some(AssocOp::Add)) | // `{ 42 } + 42` (unary plus)
+            (true, Some(AssocOp::LAnd)) | // `{ 42 } &&x` (#61475) or `{ 42 } && if x { 1 } else { 0 }`
+            (true, Some(AssocOp::LOr)) | // `{ 42 } || 42` ("logical or" or closure)
+            (true, Some(AssocOp::BitOr)) // `{ 42 } | 42` or `{ 42 } |x| 42`
+            => {
                 // These cases are ambiguous and can't be identified in the parser alone.
                 //
                 // Bitwise AND is left out because guessing intent is hard. We can make
@@ -2076,7 +2067,7 @@ fn parse_closure_expr(&mut self) -> PResult<'a, P<Expr>> {
         };
 
         let capture_clause = self.parse_capture_clause()?;
-        let fn_decl = self.parse_fn_block_decl()?;
+        let (fn_decl, fn_arg_span) = self.parse_fn_block_decl()?;
         let decl_hi = self.prev_token.span;
         let mut body = match fn_decl.output {
             FnRetTy::Default(_) => {
@@ -2117,6 +2108,7 @@ fn parse_closure_expr(&mut self) -> PResult<'a, P<Expr>> {
                 fn_decl,
                 body,
                 fn_decl_span: lo.to(decl_hi),
+                fn_arg_span,
             })),
         );
 
@@ -2145,7 +2137,9 @@ fn parse_capture_clause(&mut self) -> PResult<'a, CaptureBy> {
     }
 
     /// Parses the `|arg, arg|` header of a closure.
-    fn parse_fn_block_decl(&mut self) -> PResult<'a, P<FnDecl>> {
+    fn parse_fn_block_decl(&mut self) -> PResult<'a, (P<FnDecl>, Span)> {
+        let arg_start = self.token.span.lo();
+
         let inputs = if self.eat(&token::OrOr) {
             Vec::new()
         } else {
@@ -2161,10 +2155,11 @@ fn parse_fn_block_decl(&mut self) -> PResult<'a, P<FnDecl>> {
             self.expect_or()?;
             args
         };
+        let arg_span = self.prev_token.span.with_lo(arg_start);
         let output =
             self.parse_ret_ty(AllowPlus::Yes, RecoverQPath::Yes, RecoverReturnSign::Yes)?;
 
-        Ok(P(FnDecl { inputs, output }))
+        Ok((P(FnDecl { inputs, output }), arg_span))
     }
 
     /// Parses a parameter in a closure header (e.g., `|arg, arg|`).
index 767fb9378bef1795c386db908821b7f20e9cdf7d..beb9d55d454162d11da7442a650989fe9a72895a 100644 (file)
@@ -21,7 +21,6 @@
 use rustc_span::source_map::{self, Span};
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
 use rustc_span::DUMMY_SP;
-use std::convert::TryFrom;
 use std::mem;
 use thin_vec::ThinVec;
 use tracing::debug;
@@ -707,9 +706,9 @@ fn parse_item_list<T>(
             }
             match parse_item(self) {
                 Ok(None) => {
-                    let is_unnecessary_semicolon = !items.is_empty()
+                    let mut is_unnecessary_semicolon = !items.is_empty()
                         // When the close delim is `)` in a case like the following, `token.kind` is expected to be `token::CloseDelim(Delimiter::Parenthesis)`,
-                        // but the actual `token.kind` is `token::CloseDelim(Delimiter::Bracket)`.
+                        // but the actual `token.kind` is `token::CloseDelim(Delimiter::Brace)`.
                         // This is because the `token.kind` of the close delim is treated as the same as
                         // that of the open delim in `TokenTreesReader::parse_token_tree`, even if the delimiters of them are different.
                         // Therefore, `token.kind` should not be compared here.
@@ -728,7 +727,13 @@ fn parse_item_list<T>(
                             .span_to_snippet(self.prev_token.span)
                             .map_or(false, |snippet| snippet == "}")
                         && self.token.kind == token::Semi;
-                    let semicolon_span = self.token.span;
+                    let mut semicolon_span = self.token.span;
+                    if !is_unnecessary_semicolon {
+                        // #105369, Detect spurious `;` before assoc fn body
+                        is_unnecessary_semicolon = self.token == token::OpenDelim(Delimiter::Brace)
+                            && self.prev_token.kind == token::Semi;
+                        semicolon_span = self.prev_token.span;
+                    }
                     // We have to bail or we'll potentially never make progress.
                     let non_item_span = self.token.span;
                     let is_let = self.token.is_keyword(kw::Let);
@@ -1012,7 +1017,7 @@ fn parse_use_tree(&mut self) -> PResult<'a, UseTree> {
                     prefix.span = lo.to(self.prev_token.span);
                 }
 
-                UseTreeKind::Simple(self.parse_rename()?, DUMMY_NODE_ID, DUMMY_NODE_ID)
+                UseTreeKind::Simple(self.parse_rename()?)
             }
         };
 
@@ -1414,7 +1419,10 @@ fn parse_enum_variant(&mut self) -> PResult<'a, Option<Variant>> {
 
                 Ok((Some(vr), TrailingToken::MaybeComma))
             },
-        )
+        ).map_err(|mut err|{
+            err.help("enum variants can be `Variant`, `Variant = <integer>`, `Variant(Type, ..., TypeN)` or `Variant { fields: Types }`");
+            err
+        })
     }
 
     /// Parses `struct Foo { ... }`.
index 4d8bff28b05aa300a4ed81e7505536914837e8fd..bebb012660a16ae140a780bb5da5049761bc0faa 100644 (file)
@@ -943,6 +943,10 @@ fn parse_seq_to_before_tokens<T>(
                                 Err(e) => {
                                     // Parsing failed, therefore it must be something more serious
                                     // than just a missing separator.
+                                    for xx in &e.children {
+                                        // propagate the help message from sub error 'e' to main error 'expect_err;
+                                        expect_err.children.push(xx.clone());
+                                    }
                                     expect_err.emit();
 
                                     e.cancel();
index ff1ddfd97dfc62dc52e183f64fb1280433d44ce7..42197e6379749a264c325dbb332a41926754b515 100644 (file)
@@ -72,14 +72,22 @@ pub(crate) fn parse_stmt_without_recovery(
 
         Ok(Some(if self.token.is_keyword(kw::Let) {
             self.parse_local_mk(lo, attrs, capture_semi, force_collect)?
-        } else if self.is_kw_followed_by_ident(kw::Mut) {
-            self.recover_stmt_local(lo, attrs, InvalidVariableDeclarationSub::MissingLet)?
-        } else if self.is_kw_followed_by_ident(kw::Auto) {
+        } else if self.is_kw_followed_by_ident(kw::Mut) && self.may_recover() {
+            self.recover_stmt_local_after_let(lo, attrs, InvalidVariableDeclarationSub::MissingLet)?
+        } else if self.is_kw_followed_by_ident(kw::Auto) && self.may_recover() {
             self.bump(); // `auto`
-            self.recover_stmt_local(lo, attrs, InvalidVariableDeclarationSub::UseLetNotAuto)?
-        } else if self.is_kw_followed_by_ident(sym::var) {
+            self.recover_stmt_local_after_let(
+                lo,
+                attrs,
+                InvalidVariableDeclarationSub::UseLetNotAuto,
+            )?
+        } else if self.is_kw_followed_by_ident(sym::var) && self.may_recover() {
             self.bump(); // `var`
-            self.recover_stmt_local(lo, attrs, InvalidVariableDeclarationSub::UseLetNotVar)?
+            self.recover_stmt_local_after_let(
+                lo,
+                attrs,
+                InvalidVariableDeclarationSub::UseLetNotVar,
+            )?
         } else if self.check_path() && !self.token.is_qpath_start() && !self.is_path_start_item() {
             // We have avoided contextual keywords like `union`, items with `crate` visibility,
             // or `auto trait` items. We aim to parse an arbitrary path `a::b` but not something
@@ -213,13 +221,21 @@ fn error_outer_attrs(&self, attrs: AttrWrapper) {
         }
     }
 
-    fn recover_stmt_local(
+    fn recover_stmt_local_after_let(
         &mut self,
         lo: Span,
         attrs: AttrWrapper,
         subdiagnostic: fn(Span) -> InvalidVariableDeclarationSub,
     ) -> PResult<'a, Stmt> {
-        let stmt = self.recover_local_after_let(lo, attrs)?;
+        let stmt =
+            self.collect_tokens_trailing_token(attrs, ForceCollect::Yes, |this, attrs| {
+                let local = this.parse_local(attrs)?;
+                // FIXME - maybe capture semicolon in recovery?
+                Ok((
+                    this.mk_stmt(lo.to(this.prev_token.span), StmtKind::Local(local)),
+                    TrailingToken::None,
+                ))
+            })?;
         self.sess.emit_err(InvalidVariableDeclaration { span: lo, sub: subdiagnostic(lo) });
         Ok(stmt)
     }
@@ -243,17 +259,6 @@ fn parse_local_mk(
         })
     }
 
-    fn recover_local_after_let(&mut self, lo: Span, attrs: AttrWrapper) -> PResult<'a, Stmt> {
-        self.collect_tokens_trailing_token(attrs, ForceCollect::No, |this, attrs| {
-            let local = this.parse_local(attrs)?;
-            // FIXME - maybe capture semicolon in recovery?
-            Ok((
-                this.mk_stmt(lo.to(this.prev_token.span), StmtKind::Local(local)),
-                TrailingToken::None,
-            ))
-        })
-    }
-
     /// Parses a local variable declaration.
     fn parse_local(&mut self, attrs: AttrVec) -> PResult<'a, P<Local>> {
         let lo = self.prev_token.span;
index fcc68b3a219cc93bea57983cbe980b31a8b220c8..72da398d3fc1984282fd422763c3fb0a73fe7da5 100644 (file)
@@ -5,3 +5,4 @@ edition = "2021"
 
 [dependencies]
 rustc_lexer = { path = "../rustc_lexer" }
+rustc_data_structures = { path = "../rustc_data_structures" }
index 0113eb4e3d1029911abf26519c4b742b2e62630e..9cbe04c1288effe53ad31e764541f49ef032a23a 100644 (file)
@@ -58,13 +58,13 @@ fn to(self, end: InnerOffset) -> InnerSpan {
 
 /// A piece is a portion of the format string which represents the next part
 /// to emit. These are emitted as a stream by the `Parser` class.
-#[derive(Copy, Clone, Debug, PartialEq)]
+#[derive(Clone, Debug, PartialEq)]
 pub enum Piece<'a> {
     /// A literal string which should directly be emitted
     String(&'a str),
     /// This describes that formatting should process the next argument (as
     /// specified inside) for emission.
-    NextArgument(Argument<'a>),
+    NextArgument(Box<Argument<'a>>),
 }
 
 /// Representation of an argument specification.
@@ -244,7 +244,7 @@ fn next(&mut self) -> Option<Piece<'a>> {
                         } else {
                             self.suggest_positional_arg_instead_of_captured_arg(arg);
                         }
-                        Some(NextArgument(arg))
+                        Some(NextArgument(Box::new(arg)))
                     }
                 }
                 '}' => {
@@ -908,5 +908,9 @@ fn find_skips_from_snippet(
     (skips, true)
 }
 
+// Assert a reasonable size for `Piece`
+#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
+rustc_data_structures::static_assert_size!(Piece<'_>, 16);
+
 #[cfg(test)]
 mod tests;
index 3f9cb149b53eb402fec088035257425eca1c36e9..2992ba845ab16aab0b3da5da04096c2978ce9900 100644 (file)
@@ -76,51 +76,51 @@ fn invalid_precision() {
 fn format_nothing() {
     same(
         "{}",
-        &[NextArgument(Argument {
+        &[NextArgument(Box::new(Argument {
             position: ArgumentImplicitlyIs(0),
             position_span: InnerSpan { start: 2, end: 2 },
             format: fmtdflt(),
-        })],
+        }))],
     );
 }
 #[test]
 fn format_position() {
     same(
         "{3}",
-        &[NextArgument(Argument {
+        &[NextArgument(Box::new(Argument {
             position: ArgumentIs(3),
             position_span: InnerSpan { start: 2, end: 3 },
             format: fmtdflt(),
-        })],
+        }))],
     );
 }
 #[test]
 fn format_position_nothing_else() {
     same(
         "{3:}",
-        &[NextArgument(Argument {
+        &[NextArgument(Box::new(Argument {
             position: ArgumentIs(3),
             position_span: InnerSpan { start: 2, end: 3 },
             format: fmtdflt(),
-        })],
+        }))],
     );
 }
 #[test]
 fn format_named() {
     same(
         "{name}",
-        &[NextArgument(Argument {
+        &[NextArgument(Box::new(Argument {
             position: ArgumentNamed("name"),
             position_span: InnerSpan { start: 2, end: 6 },
             format: fmtdflt(),
-        })],
+        }))],
     )
 }
 #[test]
 fn format_type() {
     same(
         "{3:x}",
-        &[NextArgument(Argument {
+        &[NextArgument(Box::new(Argument {
             position: ArgumentIs(3),
             position_span: InnerSpan { start: 2, end: 3 },
             format: FormatSpec {
@@ -134,14 +134,14 @@ fn format_type() {
                 ty: "x",
                 ty_span: None,
             },
-        })],
+        }))],
     );
 }
 #[test]
 fn format_align_fill() {
     same(
         "{3:>}",
-        &[NextArgument(Argument {
+        &[NextArgument(Box::new(Argument {
             position: ArgumentIs(3),
             position_span: InnerSpan { start: 2, end: 3 },
             format: FormatSpec {
@@ -155,11 +155,11 @@ fn format_align_fill() {
                 ty: "",
                 ty_span: None,
             },
-        })],
+        }))],
     );
     same(
         "{3:0<}",
-        &[NextArgument(Argument {
+        &[NextArgument(Box::new(Argument {
             position: ArgumentIs(3),
             position_span: InnerSpan { start: 2, end: 3 },
             format: FormatSpec {
@@ -173,11 +173,11 @@ fn format_align_fill() {
                 ty: "",
                 ty_span: None,
             },
-        })],
+        }))],
     );
     same(
         "{3:*<abcd}",
-        &[NextArgument(Argument {
+        &[NextArgument(Box::new(Argument {
             position: ArgumentIs(3),
             position_span: InnerSpan { start: 2, end: 3 },
             format: FormatSpec {
@@ -191,14 +191,14 @@ fn format_align_fill() {
                 ty: "abcd",
                 ty_span: Some(InnerSpan::new(6, 10)),
             },
-        })],
+        }))],
     );
 }
 #[test]
 fn format_counts() {
     same(
         "{:10x}",
-        &[NextArgument(Argument {
+        &[NextArgument(Box::new(Argument {
             position: ArgumentImplicitlyIs(0),
             position_span: InnerSpan { start: 2, end: 2 },
             format: FormatSpec {
@@ -212,11 +212,11 @@ fn format_counts() {
                 ty: "x",
                 ty_span: None,
             },
-        })],
+        }))],
     );
     same(
         "{:10$.10x}",
-        &[NextArgument(Argument {
+        &[NextArgument(Box::new(Argument {
             position: ArgumentImplicitlyIs(0),
             position_span: InnerSpan { start: 2, end: 2 },
             format: FormatSpec {
@@ -230,11 +230,11 @@ fn format_counts() {
                 ty: "x",
                 ty_span: None,
             },
-        })],
+        }))],
     );
     same(
         "{1:0$.10x}",
-        &[NextArgument(Argument {
+        &[NextArgument(Box::new(Argument {
             position: ArgumentIs(1),
             position_span: InnerSpan { start: 2, end: 3 },
             format: FormatSpec {
@@ -248,11 +248,11 @@ fn format_counts() {
                 ty: "x",
                 ty_span: None,
             },
-        })],
+        }))],
     );
     same(
         "{:.*x}",
-        &[NextArgument(Argument {
+        &[NextArgument(Box::new(Argument {
             position: ArgumentImplicitlyIs(1),
             position_span: InnerSpan { start: 2, end: 2 },
             format: FormatSpec {
@@ -266,11 +266,11 @@ fn format_counts() {
                 ty: "x",
                 ty_span: None,
             },
-        })],
+        }))],
     );
     same(
         "{:.10$x}",
-        &[NextArgument(Argument {
+        &[NextArgument(Box::new(Argument {
             position: ArgumentImplicitlyIs(0),
             position_span: InnerSpan { start: 2, end: 2 },
             format: FormatSpec {
@@ -284,11 +284,11 @@ fn format_counts() {
                 ty: "x",
                 ty_span: None,
             },
-        })],
+        }))],
     );
     same(
         "{:a$.b$?}",
-        &[NextArgument(Argument {
+        &[NextArgument(Box::new(Argument {
             position: ArgumentImplicitlyIs(0),
             position_span: InnerSpan { start: 2, end: 2 },
             format: FormatSpec {
@@ -302,11 +302,11 @@ fn format_counts() {
                 ty: "?",
                 ty_span: None,
             },
-        })],
+        }))],
     );
     same(
         "{:.4}",
-        &[NextArgument(Argument {
+        &[NextArgument(Box::new(Argument {
             position: ArgumentImplicitlyIs(0),
             position_span: InnerSpan { start: 2, end: 2 },
             format: FormatSpec {
@@ -320,14 +320,14 @@ fn format_counts() {
                 ty: "",
                 ty_span: None,
             },
-        })],
+        }))],
     )
 }
 #[test]
 fn format_flags() {
     same(
         "{:-}",
-        &[NextArgument(Argument {
+        &[NextArgument(Box::new(Argument {
             position: ArgumentImplicitlyIs(0),
             position_span: InnerSpan { start: 2, end: 2 },
             format: FormatSpec {
@@ -341,11 +341,11 @@ fn format_flags() {
                 ty: "",
                 ty_span: None,
             },
-        })],
+        }))],
     );
     same(
         "{:+#}",
-        &[NextArgument(Argument {
+        &[NextArgument(Box::new(Argument {
             position: ArgumentImplicitlyIs(0),
             position_span: InnerSpan { start: 2, end: 2 },
             format: FormatSpec {
@@ -359,7 +359,7 @@ fn format_flags() {
                 ty: "",
                 ty_span: None,
             },
-        })],
+        }))],
     );
 }
 #[test]
@@ -368,7 +368,7 @@ fn format_mixture() {
         "abcd {3:x} efg",
         &[
             String("abcd "),
-            NextArgument(Argument {
+            NextArgument(Box::new(Argument {
                 position: ArgumentIs(3),
                 position_span: InnerSpan { start: 7, end: 8 },
                 format: FormatSpec {
@@ -382,7 +382,7 @@ fn format_mixture() {
                     ty: "x",
                     ty_span: None,
                 },
-            }),
+            })),
             String(" efg"),
         ],
     );
@@ -391,18 +391,18 @@ fn format_mixture() {
 fn format_whitespace() {
     same(
         "{ }",
-        &[NextArgument(Argument {
+        &[NextArgument(Box::new(Argument {
             position: ArgumentImplicitlyIs(0),
             position_span: InnerSpan { start: 2, end: 3 },
             format: fmtdflt(),
-        })],
+        }))],
     );
     same(
         "{  }",
-        &[NextArgument(Argument {
+        &[NextArgument(Box::new(Argument {
             position: ArgumentImplicitlyIs(0),
             position_span: InnerSpan { start: 2, end: 4 },
             format: fmtdflt(),
-        })],
+        }))],
     );
 }
index 5d0224c35f3645a8716d2820e8d8a4f0f49914e9..a71ae717a508d37ee42db75d1a5add8a994fac0b 100644 (file)
@@ -124,7 +124,7 @@ fn lookup_and_handle_method(&mut self, id: hir::HirId) {
     fn handle_field_access(&mut self, lhs: &hir::Expr<'_>, hir_id: hir::HirId) {
         match self.typeck_results().expr_ty_adjusted(lhs).kind() {
             ty::Adt(def, _) => {
-                let index = self.tcx.field_index(hir_id, self.typeck_results());
+                let index = self.typeck_results().field_index(hir_id);
                 self.insert_def_id(def.non_enum_variant().fields[index].did);
             }
             ty::Tuple(..) => {}
@@ -208,7 +208,7 @@ fn handle_field_pattern_match(
             if let PatKind::Wild = pat.pat.kind {
                 continue;
             }
-            let index = self.tcx.field_index(pat.hir_id, self.typeck_results());
+            let index = self.typeck_results().field_index(pat.hir_id);
             self.insert_def_id(variant.fields[index].did);
         }
     }
@@ -341,7 +341,7 @@ fn visit_node(&mut self, node: Node<'tcx>) {
     fn mark_as_used_if_union(&mut self, adt: ty::AdtDef<'tcx>, fields: &[hir::ExprField<'_>]) {
         if adt.is_union() && adt.non_enum_variant().fields.len() > 1 && adt.did().is_local() {
             for field in fields {
-                let index = self.tcx.field_index(field.hir_id, self.typeck_results());
+                let index = self.typeck_results().field_index(field.hir_id);
                 self.insert_def_id(adt.non_enum_variant().fields[index].did);
             }
         }
@@ -433,7 +433,7 @@ fn visit_pat(&mut self, pat: &'tcx hir::Pat<'tcx>) {
         self.in_pat = false;
     }
 
-    fn visit_path(&mut self, path: &'tcx hir::Path<'tcx>, _: hir::HirId) {
+    fn visit_path(&mut self, path: &hir::Path<'tcx>, _: hir::HirId) {
         self.handle_res(path.res);
         intravisit::walk_path(self, path);
     }
index 140f02c046a66c3b48d82f9a3f28acc42b3e24a5..a7854cd49988f721806864a33570b646bc5379d2 100644 (file)
@@ -369,7 +369,7 @@ fn visit_fn(
         hir_visit::walk_fn(self, fk, fd, b, id)
     }
 
-    fn visit_use(&mut self, p: &'v hir::Path<'v>, hir_id: hir::HirId) {
+    fn visit_use(&mut self, p: &'v hir::UsePath<'v>, hir_id: hir::HirId) {
         // This is `visit_use`, but the type is `Path` so record it that way.
         self.record("Path", Id::None, p);
         hir_visit::walk_use(self, p, hir_id)
@@ -442,7 +442,7 @@ fn visit_lifetime(&mut self, lifetime: &'v hir::Lifetime) {
         hir_visit::walk_lifetime(self, lifetime)
     }
 
-    fn visit_path(&mut self, path: &'v hir::Path<'v>, _id: hir::HirId) {
+    fn visit_path(&mut self, path: &hir::Path<'v>, _id: hir::HirId) {
         self.record("Path", Id::None, path);
         hir_visit::walk_path(self, path)
     }
index 2234837050bd9683750eb05d301c1c29d57aea36..1f65cc8b6096775368cd47562ecf3e55cf48ea4b 100644 (file)
@@ -1548,7 +1548,13 @@ fn check_unused_vars_in_pat(
                 .or_insert_with(|| (ln, var, vec![id_and_sp]));
         });
 
-        let can_remove = matches!(&pat.kind, hir::PatKind::Struct(_, _, true));
+        let can_remove = match pat.kind {
+            hir::PatKind::Struct(_, fields, true) => {
+                // if all fields are shorthand, remove the struct field, otherwise, mark with _ as prefix
+                fields.iter().all(|f| f.is_shorthand)
+            }
+            _ => false,
+        };
 
         for (_, (ln, var, hir_ids_and_spans)) in vars {
             if self.used_on_entry(ln, var) {
index 88bd655d8d3849cb45a56bf98c0cc46662f7c2fa..da715523474f9bc6cb63c8da1b83880f71a67682 100644 (file)
@@ -787,7 +787,7 @@ fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
         intravisit::walk_item(self, item);
     }
 
-    fn visit_path(&mut self, path: &'tcx hir::Path<'tcx>, id: hir::HirId) {
+    fn visit_path(&mut self, path: &hir::Path<'tcx>, id: hir::HirId) {
         if let Some(def_id) = path.res.opt_def_id() {
             let method_span = path.segments.last().map(|s| s.ident.span);
             let item_is_allowed = self.tcx.check_stability_allow_unstable(
@@ -880,7 +880,7 @@ struct CheckTraitImplStable<'tcx> {
 }
 
 impl<'tcx> Visitor<'tcx> for CheckTraitImplStable<'tcx> {
-    fn visit_path(&mut self, path: &'tcx hir::Path<'tcx>, _id: hir::HirId) {
+    fn visit_path(&mut self, path: &hir::Path<'tcx>, _id: hir::HirId) {
         if let Some(def_id) = path.res.opt_def_id() {
             if let Some(stab) = self.tcx.lookup_stability(def_id) {
                 self.fully_stable &= stab.level.is_stable();
index 9e41efce9ceaf6ae56b65c6176fdd28d1deb4fe8..605cf0a93b877aa255df7aaa99cb7e7823ccfdd5 100644 (file)
@@ -66,7 +66,7 @@ fn visit_local_use(&mut self, var_id: HirId, span: Span) {
 }
 
 impl<'tcx> Visitor<'tcx> for CaptureCollector<'_, 'tcx> {
-    fn visit_path(&mut self, path: &'tcx hir::Path<'tcx>, _: hir::HirId) {
+    fn visit_path(&mut self, path: &hir::Path<'tcx>, _: hir::HirId) {
         if let Res::Local(var_id) = path.res {
             self.visit_local_use(var_id, path.span);
         }
index f2177a7c28332432c41eae1ce32fd81409a454f8..a254c892478cf19815f2ccf79e670f3db96f08dd 100644 (file)
@@ -1065,9 +1065,9 @@ fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) {
                 // are checked for privacy (RFC 736). Rather than computing the set of
                 // unmentioned fields, just check them all.
                 for (vf_index, variant_field) in variant.fields.iter().enumerate() {
-                    let field = fields.iter().find(|f| {
-                        self.tcx.field_index(f.hir_id, self.typeck_results()) == vf_index
-                    });
+                    let field = fields
+                        .iter()
+                        .find(|f| self.typeck_results().field_index(f.hir_id) == vf_index);
                     let (use_ctxt, span) = match field {
                         Some(field) => (field.ident.span, field.span),
                         None => (base.span, base.span),
@@ -1077,7 +1077,7 @@ fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) {
             } else {
                 for field in fields {
                     let use_ctxt = field.ident.span;
-                    let index = self.tcx.field_index(field.hir_id, self.typeck_results());
+                    let index = self.typeck_results().field_index(field.hir_id);
                     self.check_field(use_ctxt, field.span, adt, &variant.fields[index], false);
                 }
             }
@@ -1093,7 +1093,7 @@ fn visit_pat(&mut self, pat: &'tcx hir::Pat<'tcx>) {
             let variant = adt.variant_of_res(res);
             for field in fields {
                 let use_ctxt = field.ident.span;
-                let index = self.tcx.field_index(field.hir_id, self.typeck_results());
+                let index = self.typeck_results().field_index(field.hir_id);
                 self.check_field(use_ctxt, field.span, adt, &variant.fields[index], false);
             }
         }
index e44857a023857f4a928062c44ca6d776defcf48b..0e7d628c1eb630c030946079bfaa9259a3785c01 100644 (file)
@@ -46,7 +46,7 @@ impl DepNodeIndex {
     pub const FOREVER_RED_NODE: DepNodeIndex = DepNodeIndex::from_u32(1);
 }
 
-impl std::convert::From<DepNodeIndex> for QueryInvocationId {
+impl From<DepNodeIndex> for QueryInvocationId {
     #[inline]
     fn from(dep_node_index: DepNodeIndex) -> Self {
         QueryInvocationId(dep_node_index.as_u32())
@@ -510,7 +510,7 @@ pub fn with_feed_task<Ctxt: DepContext<DepKind = K>, A: Debug, R: Debug>(
         cx: Ctxt,
         key: A,
         result: &R,
-        hash_result: fn(&mut StableHashingContext<'_>, &R) -> Fingerprint,
+        hash_result: Option<fn(&mut StableHashingContext<'_>, &R) -> Fingerprint>,
     ) -> DepNodeIndex {
         if let Some(data) = self.data.as_ref() {
             // The caller query has more dependencies than the node we are creating.  We may
@@ -521,10 +521,12 @@ pub fn with_feed_task<Ctxt: DepContext<DepKind = K>, A: Debug, R: Debug>(
             // For sanity, we still check that the loaded stable hash and the new one match.
             if let Some(dep_node_index) = self.dep_node_index_of_opt(&node) {
                 let _current_fingerprint =
-                    crate::query::incremental_verify_ich(cx, result, &node, Some(hash_result));
+                    crate::query::incremental_verify_ich(cx, result, &node, hash_result);
 
                 #[cfg(debug_assertions)]
-                data.current.record_edge(dep_node_index, node, _current_fingerprint);
+                if hash_result.is_some() {
+                    data.current.record_edge(dep_node_index, node, _current_fingerprint);
+                }
 
                 return dep_node_index;
             }
@@ -532,14 +534,16 @@ pub fn with_feed_task<Ctxt: DepContext<DepKind = K>, A: Debug, R: Debug>(
             let mut edges = SmallVec::new();
             K::read_deps(|task_deps| match task_deps {
                 TaskDepsRef::Allow(deps) => edges.extend(deps.lock().reads.iter().copied()),
-                TaskDepsRef::Ignore | TaskDepsRef::Forbid => {
+                TaskDepsRef::Ignore => {} // During HIR lowering, we have no dependencies.
+                TaskDepsRef::Forbid => {
                     panic!("Cannot summarize when dependencies are not recorded.")
                 }
             });
 
             let hashing_timer = cx.profiler().incr_result_hashing();
-            let current_fingerprint =
-                cx.with_stable_hashing_context(|mut hcx| hash_result(&mut hcx, result));
+            let current_fingerprint = hash_result.map(|hash_result| {
+                cx.with_stable_hashing_context(|mut hcx| hash_result(&mut hcx, result))
+            });
 
             let print_status = cfg!(debug_assertions) && cx.sess().opts.unstable_opts.dep_tasks;
 
@@ -549,7 +553,7 @@ pub fn with_feed_task<Ctxt: DepContext<DepKind = K>, A: Debug, R: Debug>(
                 &data.previous,
                 node,
                 edges,
-                Some(current_fingerprint),
+                current_fingerprint,
                 print_status,
             );
 
index 3b20ec70d73cb3d5dc45a48f893af8ced9e07149..d292f4beef2ebccc33f0bebfa0894a7d756e5a1a 100644 (file)
@@ -22,7 +22,6 @@
 use rustc_serialize::opaque::{FileEncodeResult, FileEncoder, IntEncodedWithFixedSize, MemDecoder};
 use rustc_serialize::{Decodable, Decoder, Encodable};
 use smallvec::SmallVec;
-use std::convert::TryInto;
 
 // The maximum value of `SerializedDepNodeIndex` leaves the upper two bits
 // unused so that we can store multiple index types in `CompressedHybridIndex`,
index 6378ec10875d038e087236d195810b573ff6c48b..163da59edd5c7378fe43f9f8c565ae1237d72693 100644 (file)
@@ -6,9 +6,8 @@
 use rustc_data_structures::sync::Lrc;
 use rustc_hir as hir;
 use rustc_hir::def_id::{DefId, LocalDefId};
-use rustc_hir::definitions::{DefPathHash, Definitions};
-use rustc_index::vec::IndexVec;
-use rustc_session::cstore::CrateStore;
+use rustc_hir::definitions::DefPathHash;
+use rustc_session::cstore::Untracked;
 use rustc_session::Session;
 use rustc_span::source_map::SourceMap;
 use rustc_span::symbol::Symbol;
@@ -20,9 +19,7 @@
 /// things (e.g., each `DefId`/`DefPath` is only hashed once).
 #[derive(Clone)]
 pub struct StableHashingContext<'a> {
-    definitions: &'a Definitions,
-    cstore: &'a dyn CrateStore,
-    source_span: &'a IndexVec<LocalDefId, Span>,
+    untracked: &'a Untracked,
     // The value of `-Z incremental-ignore-spans`.
     // This field should only be used by `unstable_opts_incremental_ignore_span`
     incremental_ignore_spans: bool,
@@ -49,19 +46,12 @@ pub(super) enum BodyResolver<'tcx> {
 
 impl<'a> StableHashingContext<'a> {
     #[inline]
-    pub fn new(
-        sess: &'a Session,
-        definitions: &'a Definitions,
-        cstore: &'a dyn CrateStore,
-        source_span: &'a IndexVec<LocalDefId, Span>,
-    ) -> Self {
+    pub fn new(sess: &'a Session, untracked: &'a Untracked) -> Self {
         let hash_spans_initial = !sess.opts.unstable_opts.incremental_ignore_spans;
 
         StableHashingContext {
             body_resolver: BodyResolver::Forbidden,
-            definitions,
-            cstore,
-            source_span,
+            untracked,
             incremental_ignore_spans: sess.opts.unstable_opts.incremental_ignore_spans,
             caching_source_map: None,
             raw_source_map: sess.source_map(),
@@ -100,13 +90,13 @@ pub fn def_path_hash(&self, def_id: DefId) -> DefPathHash {
         if let Some(def_id) = def_id.as_local() {
             self.local_def_path_hash(def_id)
         } else {
-            self.cstore.def_path_hash(def_id)
+            self.untracked.cstore.def_path_hash(def_id)
         }
     }
 
     #[inline]
     pub fn local_def_path_hash(&self, def_id: LocalDefId) -> DefPathHash {
-        self.definitions.def_path_hash(def_id)
+        self.untracked.definitions.read().def_path_hash(def_id)
     }
 
     #[inline]
@@ -156,7 +146,7 @@ fn def_path_hash(&self, def_id: DefId) -> DefPathHash {
 
     #[inline]
     fn def_span(&self, def_id: LocalDefId) -> Span {
-        *self.source_span.get(def_id).unwrap_or(&DUMMY_SP)
+        *self.untracked.source_span.get(def_id).unwrap_or(&DUMMY_SP)
     }
 
     #[inline]
index 4c4680b5d8ea89b7d241e548a0e386da06e998df..f65846fc77f6e5114bfd384ce37c013c61e10e62 100644 (file)
@@ -9,7 +9,6 @@
 use rustc_data_structures::sync::Lock;
 use rustc_data_structures::sync::WorkerLocal;
 use rustc_index::vec::{Idx, IndexVec};
-use std::default::Default;
 use std::fmt::Debug;
 use std::hash::Hash;
 use std::marker::PhantomData;
index 49bbcf57804596623ed30642d0d837d5ba1ca8af..701bbde6ad23f92d89169ce3aa3e3c7bc278685c 100644 (file)
@@ -22,8 +22,8 @@
     rustc_data_structures::{jobserver, OnDrop},
     rustc_rayon_core as rayon_core,
     rustc_span::DUMMY_SP,
-    std::iter::{self, FromIterator},
-    std::{mem, process},
+    std::iter,
+    std::process,
 };
 
 /// Represents a span and a query key.
@@ -247,7 +247,7 @@ fn wait_on_inner(&self, waiter: &Lrc<QueryWaiter>) {
             jobserver::release_thread();
             waiter.condvar.wait(&mut info);
             // Release the lock before we potentially block in `acquire_thread`
-            mem::drop(info);
+            drop(info);
             jobserver::acquire_thread();
         }
     }
index 91ac442431dfe0335cc4e8c37673557ba2c6e371..f4a6a08df1c8514fe24987fce26eb2827b7afcc4 100644 (file)
@@ -445,19 +445,13 @@ fn build_reduced_graph_for_use_tree(
             prefix.is_empty() || prefix.len() == 1 && prefix[0].ident.name == kw::PathRoot
         };
         match use_tree.kind {
-            ast::UseTreeKind::Simple(rename, id1, id2) => {
+            ast::UseTreeKind::Simple(rename) => {
                 let mut ident = use_tree.ident();
                 let mut module_path = prefix;
                 let mut source = module_path.pop().unwrap();
                 let mut type_ns_only = false;
 
                 self.r.visibilities.insert(self.r.local_def_id(id), vis);
-                if id1 != ast::DUMMY_NODE_ID {
-                    self.r.visibilities.insert(self.r.local_def_id(id1), vis);
-                }
-                if id2 != ast::DUMMY_NODE_ID {
-                    self.r.visibilities.insert(self.r.local_def_id(id2), vis);
-                }
 
                 if nested {
                     // Correctly handle `self`
@@ -565,7 +559,6 @@ fn build_reduced_graph_for_use_tree(
                     type_ns_only,
                     nested,
                     id,
-                    additional_ids: (id1, id2),
                 };
 
                 self.add_import(module_path, kind, use_tree.span, item, root_span, item.id, vis);
@@ -621,11 +614,7 @@ fn build_reduced_graph_for_use_tree(
                     let new_span = prefix[prefix.len() - 1].ident.span;
                     let tree = ast::UseTree {
                         prefix: ast::Path::from_ident(Ident::new(kw::SelfLower, new_span)),
-                        kind: ast::UseTreeKind::Simple(
-                            Some(Ident::new(kw::Underscore, new_span)),
-                            ast::DUMMY_NODE_ID,
-                            ast::DUMMY_NODE_ID,
-                        ),
+                        kind: ast::UseTreeKind::Simple(Some(Ident::new(kw::Underscore, new_span))),
                         span: use_tree.span,
                     };
                     self.build_reduced_graph_for_use_tree(
@@ -847,12 +836,11 @@ fn build_reduced_graph_for_extern_crate(
         } else if orig_name == Some(kw::SelfLower) {
             Some(self.r.graph_root)
         } else {
-            self.r.crate_loader.process_extern_crate(item, &self.r.definitions, local_def_id).map(
-                |crate_id| {
-                    self.r.extern_crate_map.insert(local_def_id, crate_id);
-                    self.r.expect_module(crate_id.as_def_id())
-                },
-            )
+            let crate_id = self.r.crate_loader().process_extern_crate(item, local_def_id);
+            crate_id.map(|crate_id| {
+                self.r.extern_crate_map.insert(local_def_id, crate_id);
+                self.r.expect_module(crate_id.as_def_id())
+            })
         }
         .map(|module| {
             let used = self.process_macro_use_imports(item, module);
index bf2428e1731a6aa8b886094d584f0a8c8dfc6053..2764a6c28a5e934bc7b74c27acfdf1ad372ece0a 100644 (file)
@@ -158,14 +158,6 @@ fn visit_fn(&mut self, fn_kind: FnKind<'a>, span: Span, _: NodeId) {
 
     fn visit_use_tree(&mut self, use_tree: &'a UseTree, id: NodeId, _nested: bool) {
         self.create_def(id, DefPathData::Use, use_tree.span);
-        match use_tree.kind {
-            UseTreeKind::Simple(_, id1, id2) => {
-                self.create_def(id1, DefPathData::Use, use_tree.prefix.span);
-                self.create_def(id2, DefPathData::Use, use_tree.prefix.span);
-            }
-            UseTreeKind::Glob => (),
-            UseTreeKind::Nested(..) => {}
-        }
         visit::walk_use_tree(self, use_tree, id);
     }
 
index bc3a710e84bd046b9213e2086f850d30f47236e8..37771693417b35a8c60d0e571ed98f7dab77a718 100644 (file)
@@ -153,7 +153,7 @@ fn report_with_use_injections(&mut self, krate: &Crate) {
             if !candidates.is_empty() {
                 show_candidates(
                     &self.session,
-                    &self.source_span,
+                    &self.untracked.source_span,
                     &mut err,
                     span,
                     &candidates,
@@ -682,7 +682,7 @@ pub(crate) fn into_struct_error(
                     }
                     show_candidates(
                         &self.session,
-                        &self.source_span,
+                        &self.untracked.source_span,
                         &mut err,
                         Some(span),
                         &import_suggestions,
@@ -1298,7 +1298,8 @@ pub(crate) fn lookup_import_candidates<FilterFn>(
                     // otherwise cause duplicate suggestions.
                     continue;
                 }
-                if let Some(crate_id) = self.crate_loader.maybe_process_path_extern(ident.name) {
+                let crate_id = self.crate_loader().maybe_process_path_extern(ident.name);
+                if let Some(crate_id) = crate_id {
                     let crate_root = self.expect_module(crate_id.as_def_id());
                     suggestions.extend(self.lookup_import_candidates_from_module(
                         lookup_ident,
@@ -1335,7 +1336,7 @@ pub(crate) fn unresolved_macro_suggestions(
             self.lookup_import_candidates(ident, Namespace::MacroNS, parent_scope, is_expected);
         show_candidates(
             &self.session,
-            &self.source_span,
+            &self.untracked.source_span,
             err,
             None,
             &import_suggestions,
@@ -1840,13 +1841,16 @@ pub(crate) fn report_path_resolution_error(
 
             (format!("use of undeclared type `{}`", ident), suggestion)
         } else {
-            let suggestion = if ident.name == sym::alloc {
-                Some((
+            let mut suggestion = None;
+            if ident.name == sym::alloc {
+                suggestion = Some((
                     vec![],
                     String::from("add `extern crate alloc` to use the `alloc` crate"),
                     Applicability::MaybeIncorrect,
                 ))
-            } else {
+            }
+
+            suggestion = suggestion.or_else(|| {
                 self.find_similarly_named_module_or_crate(ident.name, &parent_scope.module).map(
                     |sugg| {
                         (
@@ -1856,7 +1860,7 @@ pub(crate) fn report_path_resolution_error(
                         )
                     },
                 )
-            };
+            });
             (format!("use of undeclared crate or module `{}`", ident), suggestion)
         }
     }
index 3aa8d52db038173b57eab84b0da899cefa0a9120..b8efa3f8b2743336dc894dcbac137b8a0047da94 100644 (file)
@@ -1,4 +1,4 @@
-use crate::{ImportKind, NameBinding, NameBindingKind, Resolver, ResolverTree};
+use crate::{NameBinding, NameBindingKind, Resolver, ResolverTree};
 use rustc_ast::ast;
 use rustc_ast::visit;
 use rustc_ast::visit::Visitor;
@@ -104,28 +104,11 @@ pub fn compute_effective_visibilities<'c>(r: &'r mut Resolver<'a>, krate: &'c Cr
         for (binding, eff_vis) in visitor.import_effective_visibilities.iter() {
             let NameBindingKind::Import { import, .. } = binding.kind else { unreachable!() };
             if let Some(node_id) = import.id() {
-                let mut update = |node_id| {
-                    r.effective_visibilities.update_eff_vis(
-                        r.local_def_id(node_id),
-                        eff_vis,
-                        ResolverTree(&r.definitions, &r.crate_loader),
-                    )
-                };
-                update(node_id);
-                if let ImportKind::Single { additional_ids: (id1, id2), .. } = import.kind {
-                    // In theory all the single import IDs have individual visibilities and
-                    // effective visibilities, but in practice these IDs go straight to HIR
-                    // where all their few uses assume that their (effective) visibility
-                    // applies to the whole syntactic `use` item. So they all get the same
-                    // value which is the maximum of all bindings. Maybe HIR for imports
-                    // shouldn't use three IDs at all.
-                    if id1 != ast::DUMMY_NODE_ID {
-                        update(id1);
-                    }
-                    if id2 != ast::DUMMY_NODE_ID {
-                        update(id2);
-                    }
-                }
+                r.effective_visibilities.update_eff_vis(
+                    r.local_def_id(node_id),
+                    eff_vis,
+                    ResolverTree(&r.untracked),
+                )
             }
         }
 
index 2366b94732e0e8f38c4553fa632167e63dcc870c..4d896b055268e975ab284861e93a8c85a4e70cda 100644 (file)
@@ -4,7 +4,10 @@
 use crate::Determinacy::{self, *};
 use crate::Namespace::*;
 use crate::{module_to_string, names_to_string, ImportSuggestion};
-use crate::{AmbiguityKind, BindingKey, ModuleKind, ResolutionError, Resolver, Segment};
+use crate::{
+    AmbiguityError, AmbiguityErrorMisc, AmbiguityKind, BindingKey, ModuleKind, ResolutionError,
+    Resolver, Segment,
+};
 use crate::{Finalize, Module, ModuleOrUniformRoot, ParentScope, PerNS, ScopeSet};
 use crate::{NameBinding, NameBindingKind, PathResult};
 
@@ -56,9 +59,6 @@ pub enum ImportKind<'a> {
         /// If this is the import for `foo::bar::a`, we would have the ID of the `UseTree`
         /// for `a` in this field.
         id: NodeId,
-        /// Additional `NodeId`s allocated to a `ast::UseTree` for automatically generated `use` statement
-        /// (eg. implicit struct constructors)
-        additional_ids: (NodeId, NodeId),
     },
     Glob {
         is_prelude: bool,
@@ -88,7 +88,6 @@ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
                 ref type_ns_only,
                 ref nested,
                 ref id,
-                ref additional_ids,
                 // Ignore the following to avoid an infinite loop while printing.
                 source_bindings: _,
                 target_bindings: _,
@@ -99,7 +98,6 @@ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
                 .field("type_ns_only", type_ns_only)
                 .field("nested", nested)
                 .field("id", id)
-                .field("additional_ids", additional_ids)
                 .finish_non_exhaustive(),
             Glob { ref is_prelude, ref max_vis, ref id } => f
                 .debug_struct("Glob")
@@ -543,7 +541,7 @@ fn throw_unresolved_import_error(&self, errors: Vec<(String, UnresolvedImportErr
             if let Some(candidate) = &err.candidate {
                 import_candidates(
                     self.r.session,
-                    &self.r.source_span,
+                    &self.r.untracked.source_span,
                     &mut diag,
                     Some(err.span),
                     &candidate,
@@ -796,7 +794,7 @@ fn finalize_import(&mut self, import: &'b Import<'b>) -> Option<UnresolvedImport
                 match binding {
                     Ok(binding) => {
                         // Consistency checks, analogous to `finalize_macro_resolutions`.
-                        let initial_res = source_bindings[ns].get().map(|initial_binding| {
+                        let initial_binding = source_bindings[ns].get().map(|initial_binding| {
                             all_ns_err = false;
                             if let Some(target_binding) = target_bindings[ns].get() {
                                 if target.name == kw::Underscore
@@ -810,12 +808,20 @@ fn finalize_import(&mut self, import: &'b Import<'b>) -> Option<UnresolvedImport
                                     );
                                 }
                             }
-                            initial_binding.res()
+                            initial_binding
                         });
                         let res = binding.res();
-                        if let Ok(initial_res) = initial_res {
+                        if let Ok(initial_binding) = initial_binding {
+                            let initial_res = initial_binding.res();
                             if res != initial_res && this.ambiguity_errors.is_empty() {
-                                span_bug!(import.span, "inconsistent resolution for an import");
+                                this.ambiguity_errors.push(AmbiguityError {
+                                    kind: AmbiguityKind::Import,
+                                    ident,
+                                    b1: initial_binding,
+                                    b2: binding,
+                                    misc1: AmbiguityErrorMisc::None,
+                                    misc2: AmbiguityErrorMisc::None,
+                                });
                             }
                         } else if res != Res::Err
                             && this.ambiguity_errors.is_empty()
index 2d2408c061ee265559b9ad25ed18a633b5c7db75..cf3e5946053fe514f5b9195784e93e37d63e053f 100644 (file)
@@ -1927,7 +1927,7 @@ enum Elision {
                                 // We have a single lifetime => success.
                                 elision_lifetime = Elision::Param(res)
                             } else {
-                                // We have have multiple lifetimes => error.
+                                // We have multiple lifetimes => error.
                                 elision_lifetime = Elision::Err;
                             }
                         }
@@ -2360,8 +2360,8 @@ fn with_generic_param_rib<'c, F>(
                     if let GenericParamKind::Lifetime = param.kind {
                         // Record lifetime res, so lowering knows there is something fishy.
                         self.record_lifetime_param(param.id, LifetimeRes::Error);
-                        continue;
                     }
+                    continue;
                 }
                 Entry::Vacant(entry) => {
                     entry.insert(param.ident.span);
@@ -3365,13 +3365,13 @@ fn smart_resolve_path_fragment(
             // Before we start looking for candidates, we have to get our hands
             // on the type user is trying to perform invocation on; basically:
             // we're transforming `HashMap::new` into just `HashMap`.
-            let path = match path.split_last() {
+            let prefix_path = match path.split_last() {
                 Some((_, path)) if !path.is_empty() => path,
                 _ => return Some(parent_err),
             };
 
             let (mut err, candidates) =
-                this.smart_resolve_report_errors(path, path_span, PathSource::Type, None);
+                this.smart_resolve_report_errors(prefix_path, path_span, PathSource::Type, None);
 
             // There are two different error messages user might receive at
             // this point:
@@ -3415,11 +3415,23 @@ fn append_result<T, E>(res1: &mut Result<Vec<T>, E>, res2: Result<Vec<T>, E>) {
 
             if this.should_report_errs() {
                 if candidates.is_empty() {
-                    // When there is no suggested imports, we can just emit the error
-                    // and suggestions immediately. Note that we bypass the usually error
-                    // reporting routine (ie via `self.r.report_error`) because we need
-                    // to post-process the `ResolutionError` above.
-                    err.emit();
+                    if path.len() == 2 && prefix_path.len() == 1 {
+                        // Delay to check whether methond name is an associated function or not
+                        // ```
+                        // let foo = Foo {};
+                        // foo::bar(); // possibly suggest to foo.bar();
+                        //```
+                        err.stash(
+                            prefix_path[0].ident.span,
+                            rustc_errors::StashKey::CallAssocMethod,
+                        );
+                    } else {
+                        // When there is no suggested imports, we can just emit the error
+                        // and suggestions immediately. Note that we bypass the usually error
+                        // reporting routine (ie via `self.r.report_error`) because we need
+                        // to post-process the `ResolutionError` above.
+                        err.emit();
+                    }
                 } else {
                     // If there are suggested imports, the error reporting is delayed
                     this.r.use_injections.push(UseError {
@@ -3428,7 +3440,7 @@ fn append_result<T, E>(res1: &mut Result<Vec<T>, E>, res2: Result<Vec<T>, E>) {
                         def_id,
                         instead: false,
                         suggestion: None,
-                        path: path.into(),
+                        path: prefix_path.into(),
                         is_call: source.is_call(),
                     });
                 }
index df59a350ea7c9cfbd19dc89d3ab8556717e21d7e..d43983ea8150faf15db202c7b8a242a770c81c97 100644 (file)
@@ -1663,8 +1663,10 @@ fn lookup_typo_candidate(
                         if !module.no_implicit_prelude {
                             let extern_prelude = self.r.extern_prelude.clone();
                             names.extend(extern_prelude.iter().flat_map(|(ident, _)| {
-                                self.r.crate_loader.maybe_process_path_extern(ident.name).and_then(
-                                    |crate_id| {
+                                self.r
+                                    .crate_loader()
+                                    .maybe_process_path_extern(ident.name)
+                                    .and_then(|crate_id| {
                                         let crate_mod =
                                             Res::Def(DefKind::Mod, crate_id.as_def_id());
 
@@ -1673,8 +1675,7 @@ fn lookup_typo_candidate(
                                         } else {
                                             None
                                         }
-                                    },
-                                )
+                                    })
                             }));
 
                             if let Some(prelude) = self.r.prelude {
index 4ef89cfb2554fdbc13f0dde06cbb2582a81eeb30..24e4b5bdd3f50d8f84e8d3f435062eb401e9de07 100644 (file)
@@ -29,7 +29,7 @@
 use rustc_ast::{AngleBracketedArg, Crate, Expr, ExprKind, GenericArg, GenericArgs, LitKind, Path};
 use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet};
 use rustc_data_structures::intern::Interned;
-use rustc_data_structures::sync::Lrc;
+use rustc_data_structures::sync::{Lrc, RwLock};
 use rustc_errors::{Applicability, DiagnosticBuilder, ErrorGuaranteed};
 use rustc_expand::base::{DeriveResolutions, SyntaxExtension, SyntaxExtensionKind};
 use rustc_hir::def::Namespace::*;
@@ -46,7 +46,7 @@
 use rustc_middle::ty::{self, DefIdTree, MainDefinition, RegisteredTools};
 use rustc_middle::ty::{ResolverGlobalCtxt, ResolverOutputs};
 use rustc_query_system::ich::StableHashingContext;
-use rustc_session::cstore::{CrateStore, MetadataLoaderDyn};
+use rustc_session::cstore::{CrateStore, MetadataLoaderDyn, Untracked};
 use rustc_session::lint::LintBuffer;
 use rustc_session::Session;
 use rustc_span::hygiene::{ExpnId, LocalExpnId, MacroKind, SyntaxContext, Transparency};
@@ -866,11 +866,8 @@ struct MacroData {
 pub struct Resolver<'a> {
     session: &'a Session,
 
-    definitions: Definitions,
     /// Item with a given `LocalDefId` was defined during macro expansion with ID `ExpnId`.
     expn_that_defined: FxHashMap<LocalDefId, ExpnId>,
-    /// Reference span for definitions.
-    source_span: IndexVec<LocalDefId, Span>,
 
     graph_root: Module<'a>,
 
@@ -954,7 +951,10 @@ pub struct Resolver<'a> {
     arenas: &'a ResolverArenas<'a>,
     dummy_binding: &'a NameBinding<'a>,
 
-    crate_loader: CrateLoader<'a>,
+    local_crate_name: Symbol,
+    metadata_loader: Box<MetadataLoaderDyn>,
+    untracked: Untracked,
+    used_extern_options: FxHashSet<Symbol>,
     macro_names: FxHashSet<Ident>,
     builtin_macros: FxHashMap<Symbol, BuiltinMacroState>,
     /// A small map keeping true kinds of built-in macros that appear to be fn-like on
@@ -1112,15 +1112,15 @@ fn as_mut(&mut self) -> &mut Resolver<'a> {
 /// A minimal subset of resolver that can implemenent `DefIdTree`, sometimes
 /// required to satisfy borrow checker by avoiding borrowing the whole resolver.
 #[derive(Clone, Copy)]
-struct ResolverTree<'a, 'b>(&'a Definitions, &'a CrateLoader<'b>);
+struct ResolverTree<'a>(&'a Untracked);
 
-impl DefIdTree for ResolverTree<'_, '_> {
+impl DefIdTree for ResolverTree<'_> {
     #[inline]
     fn opt_parent(self, id: DefId) -> Option<DefId> {
-        let ResolverTree(definitions, crate_loader) = self;
+        let ResolverTree(Untracked { definitions, cstore, .. }) = self;
         match id.as_local() {
-            Some(id) => definitions.def_key(id).parent,
-            None => crate_loader.cstore().def_key(id).parent,
+            Some(id) => definitions.read().def_key(id).parent,
+            None => cstore.as_any().downcast_ref::<CStore>().unwrap().def_key(id).parent,
         }
         .map(|index| DefId { index, ..id })
     }
@@ -1129,7 +1129,7 @@ fn opt_parent(self, id: DefId) -> Option<DefId> {
 impl<'a, 'b> DefIdTree for &'a Resolver<'b> {
     #[inline]
     fn opt_parent(self, id: DefId) -> Option<DefId> {
-        ResolverTree(&self.definitions, &self.crate_loader).opt_parent(id)
+        ResolverTree(&self.untracked).opt_parent(id)
     }
 }
 
@@ -1156,10 +1156,10 @@ fn create_def(
             "adding a def'n for node-id {:?} and data {:?} but a previous def'n exists: {:?}",
             node_id,
             data,
-            self.definitions.def_key(self.node_id_to_def_id[&node_id]),
+            self.untracked.definitions.read().def_key(self.node_id_to_def_id[&node_id]),
         );
 
-        let def_id = self.definitions.create_def(parent, data);
+        let def_id = self.untracked.definitions.write().create_def(parent, data);
 
         // Create the definition.
         if expn_id != ExpnId::root() {
@@ -1168,7 +1168,7 @@ fn create_def(
 
         // A relative span's parent must be an absolute span.
         debug_assert_eq!(span.data_untracked().parent, None);
-        let _id = self.source_span.push(span);
+        let _id = self.untracked.source_span.push(span);
         debug_assert_eq!(_id, def_id);
 
         // Some things for which we allocate `LocalDefId`s don't correspond to
@@ -1196,7 +1196,7 @@ impl<'a> Resolver<'a> {
     pub fn new(
         session: &'a Session,
         krate: &Crate,
-        crate_name: &str,
+        crate_name: Symbol,
         metadata_loader: Box<MetadataLoaderDyn>,
         arenas: &'a ResolverArenas<'a>,
     ) -> Resolver<'a> {
@@ -1258,9 +1258,7 @@ pub fn new(
         let mut resolver = Resolver {
             session,
 
-            definitions,
             expn_that_defined: Default::default(),
-            source_span,
 
             // The outermost module has def ID 0; this is not reflected in the
             // AST.
@@ -1311,7 +1309,14 @@ pub fn new(
                 vis: ty::Visibility::Public,
             }),
 
-            crate_loader: CrateLoader::new(session, metadata_loader, crate_name),
+            metadata_loader,
+            local_crate_name: crate_name,
+            used_extern_options: Default::default(),
+            untracked: Untracked {
+                cstore: Box::new(CStore::new(session)),
+                source_span,
+                definitions: RwLock::new(definitions),
+            },
             macro_names: FxHashSet::default(),
             builtin_macros: Default::default(),
             builtin_macro_kinds: Default::default(),
@@ -1402,9 +1407,6 @@ pub fn arenas() -> ResolverArenas<'a> {
 
     pub fn into_outputs(self) -> ResolverOutputs {
         let proc_macros = self.proc_macros.iter().map(|id| self.local_def_id(*id)).collect();
-        let definitions = self.definitions;
-        let cstore = Box::new(self.crate_loader.into_cstore());
-        let source_span = self.source_span;
         let expn_that_defined = self.expn_that_defined;
         let visibilities = self.visibilities;
         let has_pub_restricted = self.has_pub_restricted;
@@ -1416,9 +1418,8 @@ pub fn into_outputs(self) -> ResolverOutputs {
         let main_def = self.main_def;
         let confused_type_with_std_module = self.confused_type_with_std_module;
         let effective_visibilities = self.effective_visibilities;
+        let untracked = self.untracked;
         let global_ctxt = ResolverGlobalCtxt {
-            cstore,
-            source_span,
             expn_that_defined,
             visibilities,
             has_pub_restricted,
@@ -1453,16 +1454,16 @@ pub fn into_outputs(self) -> ResolverOutputs {
             builtin_macro_kinds: self.builtin_macro_kinds,
             lifetime_elision_allowed: self.lifetime_elision_allowed,
         };
-        ResolverOutputs { definitions, global_ctxt, ast_lowering }
+        ResolverOutputs { global_ctxt, ast_lowering, untracked }
     }
 
     pub fn clone_outputs(&self) -> ResolverOutputs {
         let proc_macros = self.proc_macros.iter().map(|id| self.local_def_id(*id)).collect();
-        let definitions = self.definitions.clone();
+        let definitions = self.untracked.definitions.clone();
         let cstore = Box::new(self.cstore().clone());
+        let untracked =
+            Untracked { cstore, source_span: self.untracked.source_span.clone(), definitions };
         let global_ctxt = ResolverGlobalCtxt {
-            cstore,
-            source_span: self.source_span.clone(),
             expn_that_defined: self.expn_that_defined.clone(),
             visibilities: self.visibilities.clone(),
             has_pub_restricted: self.has_pub_restricted,
@@ -1497,20 +1498,26 @@ pub fn clone_outputs(&self) -> ResolverOutputs {
             builtin_macro_kinds: self.builtin_macro_kinds.clone(),
             lifetime_elision_allowed: self.lifetime_elision_allowed.clone(),
         };
-        ResolverOutputs { definitions, global_ctxt, ast_lowering }
+        ResolverOutputs { global_ctxt, ast_lowering, untracked }
     }
 
     fn create_stable_hashing_context(&self) -> StableHashingContext<'_> {
-        StableHashingContext::new(
-            self.session,
-            &self.definitions,
-            self.crate_loader.cstore(),
-            &self.source_span,
+        StableHashingContext::new(self.session, &self.untracked)
+    }
+
+    pub fn crate_loader(&mut self) -> CrateLoader<'_> {
+        CrateLoader::new(
+            &self.session,
+            &*self.metadata_loader,
+            self.local_crate_name,
+            &mut *self.untracked.cstore.untracked_as_any().downcast_mut().unwrap(),
+            self.untracked.definitions.read(),
+            &mut self.used_extern_options,
         )
     }
 
     pub fn cstore(&self) -> &CStore {
-        self.crate_loader.cstore()
+        self.untracked.cstore.as_any().downcast_ref().unwrap()
     }
 
     fn dummy_ext(&self, macro_kind: MacroKind) -> Lrc<SyntaxExtension> {
@@ -1553,7 +1560,7 @@ pub fn resolve_crate(&mut self, krate: &Crate) {
             self.session.time("resolve_main", || self.resolve_main());
             self.session.time("resolve_check_unused", || self.check_unused(krate));
             self.session.time("resolve_report_errors", || self.report_errors(krate));
-            self.session.time("resolve_postprocess", || self.crate_loader.postprocess(krate));
+            self.session.time("resolve_postprocess", || self.crate_loader().postprocess(krate));
         });
     }
 
@@ -1871,10 +1878,10 @@ fn extern_prelude_get(&mut self, ident: Ident, finalize: bool) -> Option<&'a Nam
             } else {
                 let crate_id = if finalize {
                     let Some(crate_id) =
-                        self.crate_loader.process_path_extern(ident.name, ident.span) else { return Some(self.dummy_binding); };
+                        self.crate_loader().process_path_extern(ident.name, ident.span) else { return Some(self.dummy_binding); };
                     crate_id
                 } else {
-                    self.crate_loader.maybe_process_path_extern(ident.name)?
+                    self.crate_loader().maybe_process_path_extern(ident.name)?
                 };
                 let crate_root = self.expect_module(crate_id.as_def_id());
                 let vis = ty::Visibility::<LocalDefId>::Public;
@@ -1946,14 +1953,14 @@ pub fn get_partial_res(&self, node_id: NodeId) -> Option<PartialRes> {
     /// Retrieves the span of the given `DefId` if `DefId` is in the local crate.
     #[inline]
     pub fn opt_span(&self, def_id: DefId) -> Option<Span> {
-        def_id.as_local().map(|def_id| self.source_span[def_id])
+        def_id.as_local().map(|def_id| self.untracked.source_span[def_id])
     }
 
     /// Retrieves the name of the given `DefId`.
     #[inline]
     pub fn opt_name(&self, def_id: DefId) -> Option<Symbol> {
         let def_key = match def_id.as_local() {
-            Some(def_id) => self.definitions.def_key(def_id),
+            Some(def_id) => self.untracked.definitions.read().def_key(def_id),
             None => self.cstore().def_key(def_id),
         };
         def_key.get_opt_name()
index 8c7972f8eebb92f09698ad625382f0a49f4bfd91..b5b1602c5e0d38ad3971cb62c3c19524412063a9 100644 (file)
@@ -455,7 +455,7 @@ fn cfg_accessible(
     }
 
     fn get_proc_macro_quoted_span(&self, krate: CrateNum, id: usize) -> Span {
-        self.crate_loader.cstore().get_proc_macro_quoted_span_untracked(krate, id, self.session)
+        self.cstore().get_proc_macro_quoted_span_untracked(krate, id, self.session)
     }
 
     fn declare_proc_macro(&mut self, id: NodeId) {
index fae20c2ba5fb7f1a7200923517c19971fe8617bb..9ae07cb005bd41b0db70ee91e528cf9db13bd741 100644 (file)
@@ -111,7 +111,7 @@ fn lookup_def_id(&self, ref_id: hir::HirId) -> Option<DefId> {
         self.save_ctxt.lookup_def_id(ref_id)
     }
 
-    pub fn dump_crate_info(&mut self, name: &str) {
+    pub fn dump_crate_info(&mut self, name: Symbol) {
         let source_file = self.tcx.sess.local_crate_source_file.as_ref();
         let crate_root = source_file.map(|source_file| {
             let source_file = Path::new(source_file);
@@ -124,7 +124,7 @@ pub fn dump_crate_info(&mut self, name: &str) {
 
         let data = CratePreludeData {
             crate_id: GlobalCrateId {
-                name: name.into(),
+                name: name.to_string(),
                 disambiguator: (self.tcx.sess.local_stable_crate_id().to_u64(), 0),
             },
             crate_root: crate_root.unwrap_or_else(|| "<no source>".to_owned()),
@@ -135,7 +135,7 @@ pub fn dump_crate_info(&mut self, name: &str) {
         self.dumper.crate_prelude(data);
     }
 
-    pub fn dump_compilation_options(&mut self, input: &Input, crate_name: &str) {
+    pub fn dump_compilation_options(&mut self, input: &Input, crate_name: Symbol) {
         // Apply possible `remap-path-prefix` remapping to the input source file
         // (and don't include remapping args anymore)
         let (program, arguments) = {
@@ -185,13 +185,13 @@ fn write_segments(&mut self, segments: impl IntoIterator<Item = &'tcx hir::PathS
         }
     }
 
-    fn write_sub_paths(&mut self, path: &'tcx hir::Path<'tcx>) {
+    fn write_sub_paths<R>(&mut self, path: &'tcx hir::Path<'tcx, R>) {
         self.write_segments(path.segments)
     }
 
     // As write_sub_paths, but does not process the last ident in the path (assuming it
     // will be processed elsewhere). See note on write_sub_paths about global.
-    fn write_sub_paths_truncated(&mut self, path: &'tcx hir::Path<'tcx>) {
+    fn write_sub_paths_truncated<R>(&mut self, path: &'tcx hir::Path<'tcx, R>) {
         if let [segments @ .., _] = path.segments {
             self.write_segments(segments)
         }
index 4fa0c14715e01ece4869c52c9d56dde50faa5e05..6c310abf10ac537f78b66ef160e7acd5466eb19a 100644 (file)
@@ -36,7 +36,6 @@
 use rustc_span::*;
 
 use std::cell::Cell;
-use std::default::Default;
 use std::env;
 use std::fs::File;
 use std::io::BufWriter;
@@ -95,7 +94,7 @@ fn span_from_span(&self, span: Span) -> SpanData {
     }
 
     /// Returns path to the compilation output (e.g., libfoo-12345678.rmeta)
-    pub fn compilation_output(&self, crate_name: &str) -> PathBuf {
+    pub fn compilation_output(&self, crate_name: Symbol) -> PathBuf {
         let sess = &self.tcx.sess;
         // Save-analysis is emitted per whole session, not per each crate type
         let crate_type = sess.crate_types()[0];
@@ -594,7 +593,9 @@ pub fn get_path_res(&self, hir_id: hir::HirId) -> Res {
         match self.tcx.hir().get(hir_id) {
             Node::TraitRef(tr) => tr.path.res,
 
-            Node::Item(&hir::Item { kind: hir::ItemKind::Use(path, _), .. }) => path.res,
+            Node::Item(&hir::Item { kind: hir::ItemKind::Use(path, _), .. }) => {
+                path.res.get(0).copied().unwrap_or(Res::Err)
+            }
             Node::PathSegment(seg) => {
                 if seg.res != Res::Err {
                     seg.res
@@ -892,8 +893,8 @@ pub struct DumpHandler<'a> {
 }
 
 impl<'a> DumpHandler<'a> {
-    pub fn new(odir: Option<&'a Path>, cratename: &str) -> DumpHandler<'a> {
-        DumpHandler { odir, cratename: cratename.to_owned() }
+    pub fn new(odir: Option<&'a Path>, cratename: Symbol) -> DumpHandler<'a> {
+        DumpHandler { odir, cratename: cratename.to_string() }
     }
 
     fn output_file(&self, ctx: &SaveContext<'_>) -> (BufWriter<File>, PathBuf) {
@@ -958,7 +959,7 @@ fn save(&mut self, _: &SaveContext<'_>, analysis: &Analysis) {
 
 pub fn process_crate<'l, 'tcx, H: SaveHandler>(
     tcx: TyCtxt<'tcx>,
-    cratename: &str,
+    cratename: Symbol,
     input: &'l Input,
     config: Option<Config>,
     mut handler: H,
index 0afeb86fceb241611867c67ee4820f4e810507ac..0e0ebc79eb2e3dfdb7c65855491987d8724ee200 100644 (file)
@@ -1,6 +1,5 @@
 use crate::leb128::{self, largest_max_leb128_len};
 use crate::serialize::{Decodable, Decoder, Encodable, Encoder};
-use std::convert::TryInto;
 use std::fs::File;
 use std::io::{self, Write};
 use std::mem::MaybeUninit;
index a052f29334169ebd5d6478caf780b41fb8e4df0d..d8db86c5f6216e1643d7b1e33d881135cf096fb1 100644 (file)
@@ -13,11 +13,13 @@ rustc_hir = { path = "../rustc_hir" }
 rustc_target = { path = "../rustc_target" }
 rustc_serialize = { path = "../rustc_serialize" }
 rustc_data_structures = { path = "../rustc_data_structures" }
+rustc_index = { path = "../rustc_index" }
 rustc_span = { path = "../rustc_span" }
 rustc_fs_util = { path = "../rustc_fs_util" }
 rustc_ast = { path = "../rustc_ast" }
 rustc_lint_defs = { path = "../rustc_lint_defs" }
 smallvec = "1.8.1"
+termize = "0.1.1"
 
 [target.'cfg(unix)'.dependencies]
 libc = "0.2"
index 2336d99363fd3d8ed639b61d96d9891dcb293439..8703e5754655f3c0a39792a7813da26054e0e5e4 100644 (file)
@@ -121,7 +121,7 @@ pub fn check_expected_reuse(&self, sess: &Session) {
                         let at_least = if at_least { 1 } else { 0 };
                         IncorrectCguReuseType {
                             span: error_span.0,
-                            cgu_user_name: &cgu_user_name,
+                            cgu_user_name,
                             actual_reuse,
                             expected_reuse,
                             at_least,
index eede4d16ea378b268a91e6d8e8f50c09ac1026d8..1085bce44758fe7235929e8c7ca2b703f23cbae3 100644 (file)
@@ -19,7 +19,7 @@ pub enum SizeKind {
     Min,
 }
 
-#[derive(Clone, PartialEq, Eq, Hash, Debug)]
+#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
 pub struct FieldInfo {
     pub name: Symbol,
     pub offset: u64,
@@ -33,6 +33,7 @@ pub enum DataTypeKind {
     Union,
     Enum,
     Closure,
+    Generator,
 }
 
 #[derive(PartialEq, Eq, Hash, Debug)]
@@ -114,7 +115,7 @@ pub fn print_type_sizes(&self) {
 
             let struct_like = match kind {
                 DataTypeKind::Struct | DataTypeKind::Closure => true,
-                DataTypeKind::Enum | DataTypeKind::Union => false,
+                DataTypeKind::Enum | DataTypeKind::Union | DataTypeKind::Generator => false,
             };
             for (i, variant_info) in variants.into_iter().enumerate() {
                 let VariantInfo { ref name, kind: _, align: _, size, ref fields } = *variant_info;
index 927810351e958c1f73e7879bb8df49cbf75922f4..6de564a3a069225ebee1f06be5418c9de0e1cac1 100644 (file)
@@ -10,7 +10,7 @@
 
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 
-use rustc_data_structures::stable_hasher::ToStableHashKey;
+use rustc_data_structures::stable_hasher::{StableOrd, ToStableHashKey};
 use rustc_target::abi::Align;
 use rustc_target::spec::{PanicStrategy, SanitizerSet, SplitDebuginfo};
 use rustc_target::spec::{Target, TargetTriple, TargetWarnings, TARGETS};
@@ -32,7 +32,7 @@
 use std::collections::{BTreeMap, BTreeSet};
 use std::fmt;
 use std::hash::Hash;
-use std::iter::{self, FromIterator};
+use std::iter;
 use std::path::{Path, PathBuf};
 use std::str::{self, FromStr};
 
@@ -288,6 +288,9 @@ pub enum OutputType {
     DepInfo,
 }
 
+// Safety: Trivial C-Style enums have a stable sort order across compilation sessions.
+unsafe impl StableOrd for OutputType {}
+
 impl<HCX: HashStableContext> ToStableHashKey<HCX> for OutputType {
     type KeyType = Self;
 
@@ -622,7 +625,7 @@ pub fn path(&self, flavor: OutputType) -> PathBuf {
     /// should be placed on disk.
     pub fn output_path(&self, flavor: OutputType) -> PathBuf {
         let extension = flavor.extension();
-        self.with_directory_and_extension(&self.out_directory, &extension)
+        self.with_directory_and_extension(&self.out_directory, extension)
     }
 
     /// Gets the path where a compilation artifact of the given type for the
@@ -659,7 +662,7 @@ pub fn temp_path_ext(&self, ext: &str, codegen_unit_name: Option<&str>) -> PathB
 
         let temps_directory = self.temps_directory.as_ref().unwrap_or(&self.out_directory);
 
-        self.with_directory_and_extension(&temps_directory, &extension)
+        self.with_directory_and_extension(temps_directory, &extension)
     }
 
     pub fn with_extension(&self, extension: &str) -> PathBuf {
@@ -1159,7 +1162,7 @@ fn fill_well_known_values(&mut self) {
                 values_target_family
                     .extend(target.options.families.iter().map(|family| Symbol::intern(family)));
                 values_target_arch.insert(Symbol::intern(&target.arch));
-                values_target_endian.insert(Symbol::intern(&target.options.endian.as_str()));
+                values_target_endian.insert(Symbol::intern(target.options.endian.as_str()));
                 values_target_env.insert(Symbol::intern(&target.options.env));
                 values_target_abi.insert(Symbol::intern(&target.options.abi));
                 values_target_vendor.insert(Symbol::intern(&target.options.vendor));
@@ -1846,7 +1849,7 @@ pub fn parse_target_triple(
     match matches.opt_str("target") {
         Some(target) if target.ends_with(".json") => {
             let path = Path::new(&target);
-            TargetTriple::from_path(&path).unwrap_or_else(|_| {
+            TargetTriple::from_path(path).unwrap_or_else(|_| {
                 early_error(error_format, &format!("target file {path:?} does not exist"))
             })
         }
@@ -1992,7 +1995,7 @@ fn parse_native_lib_modifiers(
 ) -> (NativeLibKind, Option<bool>) {
     let mut verbatim = None;
     for modifier in modifiers.split(',') {
-        let (modifier, value) = match modifier.strip_prefix(&['+', '-']) {
+        let (modifier, value) = match modifier.strip_prefix(['+', '-']) {
             Some(m) => (m, modifier.starts_with('+')),
             None => early_error(
                 error_format,
@@ -2421,7 +2424,7 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
 
     let mut search_paths = vec![];
     for s in &matches.opt_strs("L") {
-        search_paths.push(SearchPath::from_cli_opt(&s, error_format));
+        search_paths.push(SearchPath::from_cli_opt(s, error_format));
     }
 
     let libs = parse_libs(matches, error_format);
index 7d4a1e212a41749c9606750faf6347358f43a1c4..7f926f7d8bc4a2cb2cd25871384eff142e0324a8 100644 (file)
@@ -6,9 +6,10 @@
 use crate::utils::NativeLibKind;
 use crate::Session;
 use rustc_ast as ast;
-use rustc_data_structures::sync::{self, MetadataRef};
-use rustc_hir::def_id::{CrateNum, DefId, StableCrateId, LOCAL_CRATE};
-use rustc_hir::definitions::{DefKey, DefPath, DefPathHash};
+use rustc_data_structures::sync::{self, MetadataRef, RwLock};
+use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, StableCrateId, LOCAL_CRATE};
+use rustc_hir::definitions::{DefKey, DefPath, DefPathHash, Definitions};
+use rustc_index::vec::IndexVec;
 use rustc_span::hygiene::{ExpnHash, ExpnId};
 use rustc_span::symbol::Symbol;
 use rustc_span::Span;
@@ -217,6 +218,7 @@ pub trait MetadataLoader {
 /// during resolve)
 pub trait CrateStore: std::fmt::Debug {
     fn as_any(&self) -> &dyn Any;
+    fn untracked_as_any(&mut self) -> &mut dyn Any;
 
     // Foreign definitions.
     // This information is safe to access, since it's hashed as part of the DefPathHash, which incr.
@@ -249,3 +251,11 @@ fn expn_hash_to_expn_id(
 }
 
 pub type CrateStoreDyn = dyn CrateStore + sync::Sync;
+
+#[derive(Debug)]
+pub struct Untracked {
+    pub cstore: Box<CrateStoreDyn>,
+    /// Reference span for definitions.
+    pub source_span: IndexVec<LocalDefId, Span>,
+    pub definitions: RwLock<Definitions>,
+}
index 9aa8a06c6d36e3d39c5b51f0d2afee2712a300cc..ee492f802a70c08d21fcd119dc81755cb307aa4e 100644 (file)
@@ -129,10 +129,10 @@ pub struct FileIsNotWriteable<'a> {
 
 #[derive(Diagnostic)]
 #[diag(session_crate_name_does_not_match)]
-pub struct CrateNameDoesNotMatch<'a> {
+pub struct CrateNameDoesNotMatch {
     #[primary_span]
     pub span: Span,
-    pub s: &'a str,
+    pub s: Symbol,
     pub name: Symbol,
 }
 
@@ -151,11 +151,11 @@ pub struct CrateNameEmpty {
 
 #[derive(Diagnostic)]
 #[diag(session_invalid_character_in_create_name)]
-pub struct InvalidCharacterInCrateName<'a> {
+pub struct InvalidCharacterInCrateName {
     #[primary_span]
     pub span: Option<Span>,
     pub character: char,
-    pub crate_name: &'a str,
+    pub crate_name: Symbol,
 }
 
 #[derive(Subdiagnostic)]
@@ -317,7 +317,7 @@ fn fix_base_capitalisation(s: &str) -> Option<String> {
         LitError::InvalidIntSuffix => {
             let suf = suffix.expect("suffix error with no suffix");
             let suf = suf.as_str();
-            if looks_like_width_suffix(&['i', 'u'], &suf) {
+            if looks_like_width_suffix(&['i', 'u'], suf) {
                 // If it looks like a width, try to be helpful.
                 sess.emit_err(InvalidIntLiteralWidth { span, width: suf[1..].into() });
             } else if let Some(fixed) = fix_base_capitalisation(suf) {
index 1b66773be6f0804a02627989199547c8c6616769..1855a49c1ecdf36b331a92e362feaa3f54eec1d5 100644 (file)
@@ -3,7 +3,6 @@
 use smallvec::{smallvec, SmallVec};
 use std::env;
 use std::fs;
-use std::iter::FromIterator;
 use std::path::{Path, PathBuf};
 
 use crate::search_paths::{PathKind, SearchPath};
index f9ee202466f67964ced1c4cafab319f51ab44733..dab9c736d14d59d496f8bbed8b2e2d52f57a5980 100644 (file)
@@ -368,7 +368,7 @@ mod desc {
     pub const parse_opt_panic_strategy: &str = parse_panic_strategy;
     pub const parse_oom_strategy: &str = "either `panic` or `abort`";
     pub const parse_relro_level: &str = "one of: `full`, `partial`, or `off`";
-    pub const parse_sanitizers: &str = "comma separated list of sanitizers: `address`, `cfi`, `hwaddress`, `leak`, `memory`, `memtag`, `shadow-call-stack`, or `thread`";
+    pub const parse_sanitizers: &str = "comma separated list of sanitizers: `address`, `cfi`, `hwaddress`, `kcfi`, `leak`, `memory`, `memtag`, `shadow-call-stack`, or `thread`";
     pub const parse_sanitizer_memory_track_origins: &str = "0, 1, or 2";
     pub const parse_cfguard: &str =
         "either a boolean (`yes`, `no`, `on`, `off`, etc), `checks`, or `nochecks`";
@@ -675,6 +675,7 @@ pub(crate) fn parse_sanitizers(slot: &mut SanitizerSet, v: Option<&str>) -> bool
                 *slot |= match s {
                     "address" => SanitizerSet::ADDRESS,
                     "cfi" => SanitizerSet::CFI,
+                    "kcfi" => SanitizerSet::KCFI,
                     "leak" => SanitizerSet::LEAK,
                     "memory" => SanitizerSet::MEMORY,
                     "memtag" => SanitizerSet::MEMTAG,
@@ -1382,6 +1383,9 @@ pub(crate) fn parse_proc_macro_execution_strategy(
         "list the symbols defined by a library crate (default: no)"),
     macro_backtrace: bool = (false, parse_bool, [UNTRACKED],
         "show macro backtraces (default: no)"),
+    maximal_hir_to_mir_coverage: bool = (false, parse_bool, [TRACKED],
+        "save as much information as possible about the correspondence between MIR and HIR \
+        as source scopes (default: no)"),
     merge_functions: Option<MergeFunctions> = (None, parse_merge_functions, [TRACKED],
         "control the operation of the MergeFunctions LLVM pass, taking \
         the same values as the target option of the same name"),
@@ -1414,8 +1418,6 @@ pub(crate) fn parse_proc_macro_execution_strategy(
         "run all passes except codegen; no output"),
     no_generate_arange_section: bool = (false, parse_no_flag, [TRACKED],
         "omit DWARF address ranges that give faster lookups"),
-    no_interleave_lints: bool = (false, parse_no_flag, [UNTRACKED],
-        "execute lints separately; allows benchmarking individual lints"),
     no_leak_check: bool = (false, parse_no_flag, [UNTRACKED],
         "disable the 'leak check' for subtyping; unsound, but useful for tests"),
     no_link: bool = (false, parse_no_flag, [TRACKED],
index 2511bee46afebef62d59842f74d192194346a3af..8ee3057de625ef3b08c9faad46c824ae9c685130 100644 (file)
@@ -7,14 +7,14 @@
 use crate::Session;
 use rustc_ast as ast;
 use rustc_span::symbol::sym;
-use rustc_span::Span;
+use rustc_span::{Span, Symbol};
 use std::path::{Path, PathBuf};
 
 pub fn out_filename(
     sess: &Session,
     crate_type: CrateType,
     outputs: &OutputFilenames,
-    crate_name: &str,
+    crate_name: Symbol,
 ) -> PathBuf {
     let default_filename = filename_for_input(sess, crate_type, crate_name, outputs);
     let out_filename = outputs
@@ -45,9 +45,9 @@ fn is_writeable(p: &Path) -> bool {
     }
 }
 
-pub fn find_crate_name(sess: &Session, attrs: &[ast::Attribute], input: &Input) -> String {
-    let validate = |s: String, span: Option<Span>| {
-        validate_crate_name(sess, &s, span);
+pub fn find_crate_name(sess: &Session, attrs: &[ast::Attribute], input: &Input) -> Symbol {
+    let validate = |s: Symbol, span: Option<Span>| {
+        validate_crate_name(sess, s, span);
         s
     };
 
@@ -59,38 +59,39 @@ pub fn find_crate_name(sess: &Session, attrs: &[ast::Attribute], input: &Input)
         sess.find_by_name(attrs, sym::crate_name).and_then(|at| at.value_str().map(|s| (at, s)));
 
     if let Some(ref s) = sess.opts.crate_name {
+        let s = Symbol::intern(s);
         if let Some((attr, name)) = attr_crate_name {
-            if name.as_str() != s {
+            if name != s {
                 sess.emit_err(CrateNameDoesNotMatch { span: attr.span, s, name });
             }
         }
-        return validate(s.clone(), None);
+        return validate(s, None);
     }
 
     if let Some((attr, s)) = attr_crate_name {
-        return validate(s.to_string(), Some(attr.span));
+        return validate(s, Some(attr.span));
     }
     if let Input::File(ref path) = *input {
         if let Some(s) = path.file_stem().and_then(|s| s.to_str()) {
             if s.starts_with('-') {
                 sess.emit_err(CrateNameInvalid { s });
             } else {
-                return validate(s.replace('-', "_"), None);
+                return validate(Symbol::intern(&s.replace('-', "_")), None);
             }
         }
     }
 
-    "rust_out".to_string()
+    Symbol::intern("rust_out")
 }
 
-pub fn validate_crate_name(sess: &Session, s: &str, sp: Option<Span>) {
+pub fn validate_crate_name(sess: &Session, s: Symbol, sp: Option<Span>) {
     let mut err_count = 0;
     {
         if s.is_empty() {
             err_count += 1;
             sess.emit_err(CrateNameEmpty { span: sp });
         }
-        for c in s.chars() {
+        for c in s.as_str().chars() {
             if c.is_alphanumeric() {
                 continue;
             }
@@ -109,7 +110,7 @@ pub fn validate_crate_name(sess: &Session, s: &str, sp: Option<Span>) {
 
 pub fn filename_for_metadata(
     sess: &Session,
-    crate_name: &str,
+    crate_name: Symbol,
     outputs: &OutputFilenames,
 ) -> PathBuf {
     // If the command-line specified the path, use that directly.
@@ -132,7 +133,7 @@ pub fn filename_for_metadata(
 pub fn filename_for_input(
     sess: &Session,
     crate_type: CrateType,
-    crate_name: &str,
+    crate_name: Symbol,
     outputs: &OutputFilenames,
 ) -> PathBuf {
     let libname = format!("{}{}", crate_name, sess.opts.cg.extra_filename);
index e99e460913ef0f8799cd5d9412b59e11b8619ff6..8859b76d28972f7b36005f035f591300f22e9b79 100644 (file)
@@ -686,6 +686,10 @@ pub fn is_sanitizer_cfi_enabled(&self) -> bool {
         self.opts.unstable_opts.sanitizer.contains(SanitizerSet::CFI)
     }
 
+    pub fn is_sanitizer_kcfi_enabled(&self) -> bool {
+        self.opts.unstable_opts.sanitizer.contains(SanitizerSet::KCFI)
+    }
+
     /// Check whether this compile session and crate type use static crt.
     pub fn crt_static(&self, crate_type: Option<CrateType>) -> bool {
         if !self.target.crt_static_respected {
@@ -952,6 +956,17 @@ pub fn first_attr_value_str_by_name(
     ) -> Option<Symbol> {
         attrs.iter().find(|at| at.has_name(name)).and_then(|at| at.value_str())
     }
+
+    pub fn diagnostic_width(&self) -> usize {
+        let default_column_width = 140;
+        if let Some(width) = self.opts.diagnostic_width {
+            width
+        } else if self.opts.unstable_opts.ui_testing {
+            default_column_width
+        } else {
+            termize::dimensions().map_or(default_column_width, |(w, _)| w)
+        }
+    }
 }
 
 // JUSTIFICATION: defn of the suggested wrapper fns
@@ -1533,6 +1548,14 @@ fn validate_commandline_args_with_session_available(sess: &Session) {
         }
     }
 
+    // LLVM CFI and KCFI are mutually exclusive
+    if sess.is_sanitizer_cfi_enabled() && sess.is_sanitizer_kcfi_enabled() {
+        sess.emit_err(CannotMixAndMatchSanitizers {
+            first: "cfi".to_string(),
+            second: "kcfi".to_string(),
+        });
+    }
+
     if sess.opts.unstable_opts.stack_protector != StackProtector::None {
         if !sess.target.options.supports_stack_protector {
             sess.emit_warning(StackProtectorNotSupportedForTarget {
index 47aa4dfba42bb9fc288a561eaef5b6875e5e216e..d3c2c5113bcdec663f1b00fb9d873d316d7bccae 100644 (file)
@@ -247,7 +247,7 @@ fn analyze_source_file_generic(
             // The slow path:
             // This is either ASCII control character "DEL" or the beginning of
             // a multibyte char. Just decode to `char`.
-            let c = (&src[i..]).chars().next().unwrap();
+            let c = src[i..].chars().next().unwrap();
             char_len = c.len_utf8();
 
             let pos = BytePos::from_usize(i) + output_offset;
index fdabf404a37fb0f0b1d76331c4d91c6d043becc5..886112769a977f78db57a95c9ddabafe985133dc 100644 (file)
@@ -165,7 +165,7 @@ pub fn span_data_to_lines_and_cols(
             Some(new_file_and_idx)
         } else {
             let file = &self.line_cache[oldest].file;
-            if !file_contains(&file, span_data.hi) {
+            if !file_contains(file, span_data.hi) {
                 return None;
             }
 
index f5555846d20a7e522691df81d4f0844328b817c2..e62ce2c266aa04ca507edd377ab92672d193a336 100644 (file)
@@ -1,4 +1,4 @@
-use crate::HashStableContext;
+use crate::{HashStableContext, Symbol};
 use rustc_data_structures::fingerprint::Fingerprint;
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher, ToStableHashKey};
 use rustc_data_structures::AtomicRef;
@@ -149,9 +149,11 @@ pub fn to_u64(self) -> u64 {
 
     /// Computes the stable ID for a crate with the given name and
     /// `-Cmetadata` arguments.
-    pub fn new(crate_name: &str, is_exe: bool, mut metadata: Vec<String>) -> StableCrateId {
+    pub fn new(crate_name: Symbol, is_exe: bool, mut metadata: Vec<String>) -> StableCrateId {
         let mut hasher = StableHasher::new();
-        crate_name.hash(&mut hasher);
+        // We must hash the string text of the crate name, not the id, as the id is not stable
+        // across builds.
+        crate_name.as_str().hash(&mut hasher);
 
         // We don't want the stable crate ID to depend on the order of
         // -C metadata arguments, so sort them:
@@ -274,7 +276,7 @@ fn cmp(&self, other: &DefId) -> std::cmp::Ordering {
 impl PartialOrd for DefId {
     #[inline]
     fn partial_cmp(&self, other: &DefId) -> Option<std::cmp::Ordering> {
-        Some(Ord::cmp(self, other))
+        Some(self.cmp(other))
     }
 }
 
index 99a8b03fa39ad27d769aea707c3c77532037c265..038699154c727dc72d9add71fc1e6ecc6f70b78c 100644 (file)
@@ -381,7 +381,7 @@ pub(crate) fn new(edition: Edition) -> Self {
     }
 
     pub fn with<T, F: FnOnce(&mut HygieneData) -> T>(f: F) -> T {
-        with_session_globals(|session_globals| f(&mut *session_globals.hygiene_data.borrow_mut()))
+        with_session_globals(|session_globals| f(&mut session_globals.hygiene_data.borrow_mut()))
     }
 
     #[inline]
index 1065cd384a94d21c5ba241154d870a0482c03fc0..335bfc3302f27c34bd0dada4f2e93840574a55f0 100644 (file)
@@ -238,7 +238,7 @@ pub fn into_local_path(self) -> Option<PathBuf> {
     pub fn remapped_path_if_available(&self) -> &Path {
         match self {
             RealFileName::LocalPath(p)
-            | RealFileName::Remapped { local_path: _, virtual_name: p } => &p,
+            | RealFileName::Remapped { local_path: _, virtual_name: p } => p,
         }
     }
 
@@ -491,6 +491,10 @@ pub fn with_parent(&self, parent: Option<LocalDefId>) -> Span {
     pub fn is_dummy(self) -> bool {
         self.lo.0 == 0 && self.hi.0 == 0
     }
+    #[inline]
+    pub fn is_visible(self, sm: &SourceMap) -> bool {
+        !self.is_dummy() && sm.is_span_accessible(self.span())
+    }
     /// Returns `true` if `self` fully encloses `other`.
     pub fn contains(self, other: Self) -> bool {
         self.lo <= other.lo && other.hi <= self.hi
@@ -556,6 +560,11 @@ pub fn is_dummy(self) -> bool {
         self.data_untracked().is_dummy()
     }
 
+    #[inline]
+    pub fn is_visible(self, sm: &SourceMap) -> bool {
+        self.data_untracked().is_visible(sm)
+    }
+
     /// Returns `true` if this span comes from any kind of macro, desugaring or inlining.
     #[inline]
     pub fn from_expansion(self) -> bool {
index 2ae57d9e56d7c5ce3ec0ff45c06bb8986fe231c2..43a3172270733ffebdc86005de630265f1b206a3 100644 (file)
 use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::stable_hasher::StableHasher;
 use rustc_data_structures::sync::{AtomicU32, Lrc, MappedReadGuard, ReadGuard, RwLock};
+use std::cmp;
 use std::hash::Hash;
 use std::path::{Path, PathBuf};
 use std::sync::atomic::Ordering;
-use std::{clone::Clone, cmp};
-use std::{convert::TryFrom, unreachable};
 
 use std::fs;
 use std::io;
index b3de6741594097b8595bfa39277dbc5382e38405..f0e91e5a6a917c3373fa399a2e496fe243ab805d 100644 (file)
@@ -166,5 +166,5 @@ fn intern(&mut self, span_data: &SpanData) -> u32 {
 // If an interner exists, return it. Otherwise, prepare a fresh one.
 #[inline]
 fn with_span_interner<T, F: FnOnce(&mut SpanInterner) -> T>(f: F) -> T {
-    crate::with_session_globals(|session_globals| f(&mut *session_globals.span_interner.lock()))
+    crate::with_session_globals(|session_globals| f(&mut session_globals.span_interner.lock()))
 }
index 739716cfce382daa5e21da8680fd270525a32a48..85d416c43f95a8512c66c4f2b0c8a99f282bee80 100644 (file)
@@ -9,7 +9,6 @@
 use rustc_macros::HashStable_Generic;
 use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
 
-use std::cmp::{Ord, PartialEq, PartialOrd};
 use std::fmt;
 use std::hash::{Hash, Hasher};
 use std::str;
         Capture,
         Center,
         Clone,
+        Context,
         Continue,
         Copy,
         Count,
         Relaxed,
         Release,
         Result,
-        ResumeTy,
         Return,
         Right,
         Rust,
         generic_associated_types_extended,
         generic_const_exprs,
         generic_param_attrs,
-        get_context,
         global_allocator,
         global_asm,
         globs,
         item_like_imports,
         iter,
         iter_repeat,
+        kcfi,
         keyword,
         kind,
         kreg,
         ty,
         type_alias_enum_variants,
         type_alias_impl_trait,
+        type_ascribe,
         type_ascription,
         type_changing_struct_update,
         type_id,
@@ -1710,7 +1710,8 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
     }
 }
 
-/// This is the most general way to print identifiers.
+/// The most general type to print identifiers.
+///
 /// AST pretty-printer is used as a fallback for turning AST structures into token streams for
 /// proc macros. Additionally, proc macros may stringify their input and expect it survive the
 /// stringification (especially true for proc macro derives written between Rust 1.15 and 1.30).
@@ -1876,7 +1877,7 @@ impl<S: Encoder> Encodable<S> for Symbol {
 impl<D: Decoder> Decodable<D> for Symbol {
     #[inline]
     default fn decode(d: &mut D) -> Symbol {
-        Symbol::intern(&d.read_str())
+        Symbol::intern(d.read_str())
     }
 }
 
@@ -1973,7 +1974,6 @@ pub mod kw {
 /// For example `sym::rustfmt` or `sym::u8`.
 pub mod sym {
     use super::Symbol;
-    use std::convert::TryInto;
 
     #[doc(inline)]
     pub use super::sym_generated::*;
index 2a29ad6a9e56b9b288de35f41a85bdf7f06d847b..4e447eab02e7c9d7e9dd581355282fa6a52de6c9 100644 (file)
@@ -10,6 +10,7 @@ bitflags = "1.2.1"
 tracing = "0.1"
 punycode = "0.4.0"
 rustc-demangle = "0.1.21"
+twox-hash = "1.6.3"
 
 rustc_span = { path = "../rustc_span" }
 rustc_middle = { path = "../rustc_middle" }
index 9228bea43f9327319d92c5c32b1360d815c92365..53983bed718922b3521462a88794d327bd5eceae 100644 (file)
@@ -3,6 +3,8 @@
 
 use rustc_middle::ty::{FnSig, Ty, TyCtxt};
 use rustc_target::abi::call::FnAbi;
+use std::hash::Hasher;
+use twox_hash::XxHash64;
 
 mod typeid_itanium_cxx_abi;
 use typeid_itanium_cxx_abi::TypeIdOptions;
@@ -16,3 +18,25 @@ pub fn typeid_for_fnabi<'tcx>(tcx: TyCtxt<'tcx>, fn_abi: &FnAbi<'tcx, Ty<'tcx>>)
 pub fn typeid_for_fnsig<'tcx>(tcx: TyCtxt<'tcx>, fn_sig: &FnSig<'tcx>) -> String {
     typeid_itanium_cxx_abi::typeid_for_fnsig(tcx, fn_sig, TypeIdOptions::NO_OPTIONS)
 }
+
+/// Returns an LLVM KCFI type metadata identifier for the specified FnAbi.
+pub fn kcfi_typeid_for_fnabi<'tcx>(tcx: TyCtxt<'tcx>, fn_abi: &FnAbi<'tcx, Ty<'tcx>>) -> u32 {
+    // An LLVM KCFI type metadata identifier is a 32-bit constant produced by taking the lower half
+    // of the xxHash64 of the type metadata identifier. (See llvm/llvm-project@cff5bef.)
+    let mut hash: XxHash64 = Default::default();
+    hash.write(
+        typeid_itanium_cxx_abi::typeid_for_fnabi(tcx, fn_abi, TypeIdOptions::NO_OPTIONS).as_bytes(),
+    );
+    hash.finish() as u32
+}
+
+/// Returns an LLVM KCFI type metadata identifier for the specified FnSig.
+pub fn kcfi_typeid_for_fnsig<'tcx>(tcx: TyCtxt<'tcx>, fn_sig: &FnSig<'tcx>) -> u32 {
+    // An LLVM KCFI type metadata identifier is a 32-bit constant produced by taking the lower half
+    // of the xxHash64 of the type metadata identifier. (See llvm/llvm-project@cff5bef.)
+    let mut hash: XxHash64 = Default::default();
+    hash.write(
+        typeid_itanium_cxx_abi::typeid_for_fnsig(tcx, fn_sig, TypeIdOptions::NO_OPTIONS).as_bytes(),
+    );
+    hash.finish() as u32
+}
index ec8f20fe692166fe30c5d7fa23e0d1015ffd4802..c8b6ac5ae25b2eb60152c2f3ae166471d0bb3f58 100644 (file)
@@ -78,7 +78,7 @@ fn arg_scalar_pair<C>(
 where
     C: HasDataLayout,
 {
-    data = arg_scalar(cx, &scalar1, offset, data);
+    data = arg_scalar(cx, scalar1, offset, data);
     match (scalar1.primitive(), scalar2.primitive()) {
         (abi::F32, _) => offset += Reg::f32().size,
         (_, abi::F64) => offset += Reg::f64().size,
@@ -90,7 +90,7 @@ fn arg_scalar_pair<C>(
     if (offset.bytes() % 4) != 0 && scalar2.primitive().is_float() {
         offset += Size::from_bytes(4 - (offset.bytes() % 4));
     }
-    data = arg_scalar(cx, &scalar2, offset, data);
+    data = arg_scalar(cx, scalar2, offset, data);
     return data;
 }
 
index b69a0a645a415913909e0dd127bff1485cfbb770..dc2cc23ffb1e40c61448af0651d18615c59eb8c9 100644 (file)
@@ -18,7 +18,6 @@
 #![deny(rustc::untranslatable_diagnostic)]
 #![deny(rustc::diagnostic_outside_of_impl)]
 
-use std::iter::FromIterator;
 use std::path::{Path, PathBuf};
 
 #[macro_use]
index 0f6bbc323174cfb45dad1ffe4a388d1d323c2234..e72cab629ff19058cd332c33689fc851ee263cc4 100644 (file)
@@ -1,4 +1,4 @@
-use super::apple_base::{macos_link_env_remove, macos_llvm_target, opts, Arch};
+use super::apple_base::{macos_llvm_target, opts, Arch};
 use crate::spec::{FramePointer, SanitizerSet, Target, TargetOptions};
 
 pub fn target() -> Target {
@@ -10,8 +10,6 @@ pub fn target() -> Target {
     // FIXME: The leak sanitizer currently fails the tests, see #88132.
     base.supported_sanitizers = SanitizerSet::ADDRESS | SanitizerSet::CFI | SanitizerSet::THREAD;
 
-    base.link_env_remove.to_mut().extend(macos_link_env_remove());
-
     Target {
         // Clang automatically chooses a more specific target based on
         // MACOSX_DEPLOYMENT_TARGET.  To enable cross-language LTO to work
index 4ae6d4120c9958978820a67141fdf7ef8edfd923..aca52e1478eb8ac44fd5294ac34a65422d27ec73 100644 (file)
@@ -6,13 +6,16 @@
 //
 // For example, `-C target-cpu=cortex-a53`.
 
-use super::{Cc, LinkerFlavor, Lld, PanicStrategy, RelocModel, Target, TargetOptions};
+use super::{
+    Cc, LinkerFlavor, Lld, PanicStrategy, RelocModel, SanitizerSet, Target, TargetOptions,
+};
 
 pub fn target() -> Target {
     let opts = TargetOptions {
         linker_flavor: LinkerFlavor::Gnu(Cc::No, Lld::Yes),
         linker: Some("rust-lld".into()),
         features: "+strict-align,+neon,+fp-armv8".into(),
+        supported_sanitizers: SanitizerSet::KCFI,
         relocation_model: RelocModel::Static,
         disable_redzone: true,
         max_atomic_width: Some(128),
index d062b36742d60550d1c639ee2ee54de642053800..3c90a5e7e93ea74ca2ae33ac230ad3522d10f841 100644 (file)
@@ -1,6 +1,6 @@
 use crate::spec::{
-    aarch64_apple_ios_sim, aarch64_apple_watchos_sim, x86_64_apple_ios, x86_64_apple_tvos,
-    x86_64_apple_watchos_sim,
+    aarch64_apple_darwin, aarch64_apple_ios_sim, aarch64_apple_watchos_sim, i686_apple_darwin,
+    x86_64_apple_darwin, x86_64_apple_ios, x86_64_apple_tvos, x86_64_apple_watchos_sim,
 };
 
 #[test]
@@ -18,3 +18,18 @@ fn simulator_targets_set_abi() {
         assert_eq!(target.abi, "sim")
     }
 }
+
+#[test]
+fn macos_link_environment_unmodified() {
+    let all_macos_targets = [
+        aarch64_apple_darwin::target(),
+        i686_apple_darwin::target(),
+        x86_64_apple_darwin::target(),
+    ];
+
+    for target in all_macos_targets {
+        // macOS targets should only remove information for cross-compiling, but never
+        // for the host.
+        assert_eq!(target.link_env_remove, crate::spec::cvs!["IPHONEOS_DEPLOYMENT_TARGET"]);
+    }
+}
index 23c826cb1bda2922558bc2859845a16ec52c26cf..fc6a2edabb763c89de1dad368dfecf7b17154b2a 100644 (file)
@@ -72,16 +72,6 @@ fn target_cpu(self) -> &'static str {
             Arm64_sim => "apple-a12",
         }
     }
-
-    fn link_env_remove(self) -> StaticCow<[StaticCow<str>]> {
-        match self {
-            Armv7 | Armv7k | Armv7s | Arm64 | Arm64_32 | I386 | I686 | X86_64 | X86_64_sim
-            | Arm64_sim => {
-                cvs!["MACOSX_DEPLOYMENT_TARGET"]
-            }
-            X86_64_macabi | Arm64_macabi => cvs!["IPHONEOS_DEPLOYMENT_TARGET"],
-        }
-    }
 }
 
 fn pre_link_args(os: &'static str, arch: Arch, abi: &'static str) -> LinkArgs {
@@ -140,7 +130,7 @@ pub fn opts(os: &'static str, arch: Arch) -> TargetOptions {
         abi: abi.into(),
         os: os.into(),
         cpu: arch.target_cpu().into(),
-        link_env_remove: arch.link_env_remove(),
+        link_env_remove: link_env_remove(arch, os),
         vendor: "apple".into(),
         linker_flavor: LinkerFlavor::Darwin(Cc::Yes, Lld::No),
         // macOS has -dead_strip, which doesn't rely on function_sections
@@ -211,20 +201,38 @@ pub fn macos_llvm_target(arch: Arch) -> String {
     format!("{}-apple-macosx{}.{}.0", arch.target_name(), major, minor)
 }
 
-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.
-    if let Ok(sdkroot) = env::var("SDKROOT") {
-        if sdkroot.contains("iPhoneOS.platform") || sdkroot.contains("iPhoneSimulator.platform") {
-            env_remove.push("SDKROOT".into())
+fn link_env_remove(arch: Arch, os: &'static str) -> StaticCow<[StaticCow<str>]> {
+    // Apple platforms only officially support macOS as a host for any compilation.
+    //
+    // If building for macOS, we go ahead and remove any erroneous environment state
+    // that's only applicable to cross-OS compilation. Always leave anything for the
+    // host OS alone though.
+    if os == "macos" {
+        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.
+        if let Ok(sdkroot) = env::var("SDKROOT") {
+            if sdkroot.contains("iPhoneOS.platform") || sdkroot.contains("iPhoneSimulator.platform")
+            {
+                env_remove.push("SDKROOT".into())
+            }
+        }
+        // Additionally, `IPHONEOS_DEPLOYMENT_TARGET` must not be set when using the Xcode linker at
+        // "/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/ld",
+        // although this is apparently ignored when using the linker at "/usr/bin/ld".
+        env_remove.push("IPHONEOS_DEPLOYMENT_TARGET".into());
+        env_remove.into()
+    } else {
+        // Otherwise if cross-compiling for a different OS/SDK, remove any part
+        // of the linking environment that's wrong and reversed.
+        match arch {
+            Armv7 | Armv7k | Armv7s | Arm64 | Arm64_32 | I386 | I686 | X86_64 | X86_64_sim
+            | Arm64_sim => {
+                cvs!["MACOSX_DEPLOYMENT_TARGET"]
+            }
+            X86_64_macabi | Arm64_macabi => cvs!["IPHONEOS_DEPLOYMENT_TARGET"],
         }
     }
-    // Additionally, `IPHONEOS_DEPLOYMENT_TARGET` must not be set when using the Xcode linker at
-    // "/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/ld",
-    // although this is apparently ignored when using the linker at "/usr/bin/ld".
-    env_remove.push("IPHONEOS_DEPLOYMENT_TARGET".into());
-    env_remove
 }
 
 fn ios_deployment_target() -> (u32, u32) {
index 8b968af5eccff330a51e7aef34044de6b6b3ef82..ad22467ba9c8970ad4cdf13b804d648b307f6cfb 100644 (file)
@@ -1,4 +1,4 @@
-use super::apple_base::{macos_link_env_remove, macos_llvm_target, opts, Arch};
+use super::apple_base::{macos_llvm_target, opts, Arch};
 use crate::spec::{Cc, FramePointer, LinkerFlavor, Lld, StackProbeType, Target, TargetOptions};
 
 pub fn target() -> Target {
@@ -7,7 +7,6 @@ pub fn target() -> Target {
     let mut base = opts("macos", arch);
     base.max_atomic_width = Some(64);
     base.add_pre_link_args(LinkerFlavor::Darwin(Cc::Yes, Lld::No), &["-m32"]);
-    base.link_env_remove.to_mut().extend(macos_link_env_remove());
     base.stack_probes = StackProbeType::X86;
     base.frame_pointer = FramePointer::Always;
 
index 78315afa759561080a7f479c8e595d5046a2c975..be994eda14c004aecca3d9e0c7e3e5bf7d8f5eb0 100644 (file)
@@ -45,9 +45,7 @@
 use serde_json::Value;
 use std::borrow::Cow;
 use std::collections::BTreeMap;
-use std::convert::TryFrom;
 use std::hash::{Hash, Hasher};
-use std::iter::FromIterator;
 use std::ops::{Deref, DerefMut};
 use std::path::{Path, PathBuf};
 use std::str::FromStr;
@@ -804,7 +802,7 @@ fn to_json(&self) -> Json {
 
 bitflags::bitflags! {
     #[derive(Default, Encodable, Decodable)]
-    pub struct SanitizerSet: u8 {
+    pub struct SanitizerSet: u16 {
         const ADDRESS = 1 << 0;
         const LEAK    = 1 << 1;
         const MEMORY  = 1 << 2;
@@ -813,6 +811,7 @@ pub struct SanitizerSet: u8 {
         const CFI     = 1 << 5;
         const MEMTAG  = 1 << 6;
         const SHADOWCALLSTACK = 1 << 7;
+        const KCFI    = 1 << 8;
     }
 }
 
@@ -824,6 +823,7 @@ pub fn as_str(self) -> Option<&'static str> {
         Some(match self {
             SanitizerSet::ADDRESS => "address",
             SanitizerSet::CFI => "cfi",
+            SanitizerSet::KCFI => "kcfi",
             SanitizerSet::LEAK => "leak",
             SanitizerSet::MEMORY => "memory",
             SanitizerSet::MEMTAG => "memtag",
@@ -859,6 +859,7 @@ fn into_iter(self) -> Self::IntoIter {
         [
             SanitizerSet::ADDRESS,
             SanitizerSet::CFI,
+            SanitizerSet::KCFI,
             SanitizerSet::LEAK,
             SanitizerSet::MEMORY,
             SanitizerSet::MEMTAG,
@@ -2327,6 +2328,7 @@ macro_rules! key {
                             base.$key_name |= match s.as_str() {
                                 Some("address") => SanitizerSet::ADDRESS,
                                 Some("cfi") => SanitizerSet::CFI,
+                                Some("kcfi") => SanitizerSet::KCFI,
                                 Some("leak") => SanitizerSet::LEAK,
                                 Some("memory") => SanitizerSet::MEMORY,
                                 Some("memtag") => SanitizerSet::MEMTAG,
@@ -2658,7 +2660,7 @@ fn load_file(path: &Path) -> Result<(Target, TargetWarnings), String> {
 
                 // Additionally look in the sysroot under `lib/rustlib/<triple>/target.json`
                 // as a fallback.
-                let rustlib_path = crate::target_rustlib_path(&sysroot, &target_triple);
+                let rustlib_path = crate::target_rustlib_path(sysroot, target_triple);
                 let p = PathBuf::from_iter([
                     Path::new(sysroot),
                     Path::new(&rustlib_path),
index 8dad941b534b6a00125de8e30e7a5ad8b01fd753..06529c2e4039d768b198ecac3558adaf95cda447 100644 (file)
@@ -33,12 +33,6 @@ pub fn target() -> Target {
             // For now this target just never has an entry symbol no matter the output
             // type, so unconditionally pass this.
             "--no-entry",
-            // Rust really needs a way for users to specify exports and imports in
-            // the source code. --export-dynamic isn't the right tool for this job,
-            // however it does have the side effect of automatically exporting a lot
-            // of symbols, which approximates what people want when compiling for
-            // wasm32-unknown-unknown expect, so use it for now.
-            "--export-dynamic",
         ],
     );
     options.add_pre_link_args(
@@ -48,7 +42,6 @@ pub fn target() -> Target {
             // otherwise
             "--target=wasm32-unknown-unknown",
             "-Wl,--no-entry",
-            "-Wl,--export-dynamic",
         ],
     );
 
index 6f0bbf0672d449d555a32beae5bad63e1b0bfe96..a0476d542e6424a1fb3ba2593dd88c3fcc406cf4 100644 (file)
@@ -104,6 +104,10 @@ pub fn target() -> Target {
     // `args::args()` makes the WASI API calls itself.
     options.main_needs_argc_argv = false;
 
+    // And, WASI mangles the name of "main" to distinguish between different
+    // signatures.
+    options.entry_name = "__main_void".into();
+
     Target {
         llvm_target: "wasm32-wasi".into(),
         pointer_width: 32,
index c053031612ce5369575731e710bdcfd395b76116..9a3e7a8050025c01cc63e69238ad78756b736213 100644 (file)
@@ -1,4 +1,4 @@
-use super::apple_base::{macos_link_env_remove, macos_llvm_target, opts, Arch};
+use super::apple_base::{macos_llvm_target, opts, Arch};
 use crate::spec::{Cc, FramePointer, LinkerFlavor, Lld, SanitizerSet};
 use crate::spec::{StackProbeType, Target, TargetOptions};
 
@@ -8,7 +8,6 @@ pub fn target() -> Target {
     base.max_atomic_width = Some(128); // core2 supports cmpxchg16b
     base.frame_pointer = FramePointer::Always;
     base.add_pre_link_args(LinkerFlavor::Darwin(Cc::Yes, Lld::No), &["-m64"]);
-    base.link_env_remove.to_mut().extend(macos_link_env_remove());
     base.stack_probes = StackProbeType::X86;
     base.supported_sanitizers =
         SanitizerSet::ADDRESS | SanitizerSet::CFI | SanitizerSet::LEAK | SanitizerSet::THREAD;
index e4d33c2b8c62d9fee2f58a716a601d254435d5a6..32060c35c11b835da211d0dee16e652294082cd8 100644 (file)
@@ -5,7 +5,7 @@
 // features.
 
 use super::{Cc, CodeModel, LinkerFlavor, Lld, PanicStrategy};
-use super::{RelroLevel, StackProbeType, Target, TargetOptions};
+use super::{RelroLevel, SanitizerSet, StackProbeType, Target, TargetOptions};
 
 pub fn target() -> Target {
     let opts = TargetOptions {
@@ -20,6 +20,7 @@ pub fn target() -> Target {
         features:
             "-mmx,-sse,-sse2,-sse3,-ssse3,-sse4.1,-sse4.2,-3dnow,-3dnowa,-avx,-avx2,+soft-float"
                 .into(),
+        supported_sanitizers: SanitizerSet::KCFI,
         disable_redzone: true,
         panic_strategy: PanicStrategy::Abort,
         code_model: Some(CodeModel::Kernel),
diff --git a/compiler/rustc_trait_selection/src/traits/codegen.rs b/compiler/rustc_trait_selection/src/traits/codegen.rs
deleted file mode 100644 (file)
index 61743d7..0000000
+++ /dev/null
@@ -1,88 +0,0 @@
-// This file contains various trait resolution methods used by codegen.
-// They all assume regions can be erased and monomorphic types.  It
-// seems likely that they should eventually be merged into more
-// general routines.
-
-use crate::infer::{DefiningAnchor, TyCtxtInferExt};
-use crate::traits::error_reporting::TypeErrCtxtExt;
-use crate::traits::{
-    ImplSource, Obligation, ObligationCause, SelectionContext, TraitEngine, TraitEngineExt,
-    Unimplemented,
-};
-use rustc_infer::traits::FulfillmentErrorCode;
-use rustc_middle::traits::CodegenObligationError;
-use rustc_middle::ty::{self, TyCtxt};
-
-/// Attempts to resolve an obligation to an `ImplSource`. The result is
-/// a shallow `ImplSource` resolution, meaning that we do not
-/// (necessarily) resolve all nested obligations on the impl. Note
-/// that type check should guarantee to us that all nested
-/// obligations *could be* resolved if we wanted to.
-///
-/// This also expects that `trait_ref` is fully normalized.
-pub fn codegen_select_candidate<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    (param_env, trait_ref): (ty::ParamEnv<'tcx>, ty::PolyTraitRef<'tcx>),
-) -> Result<&'tcx ImplSource<'tcx, ()>, CodegenObligationError> {
-    // We expect the input to be fully normalized.
-    debug_assert_eq!(trait_ref, tcx.normalize_erasing_regions(param_env, trait_ref));
-
-    // Do the initial selection for the obligation. This yields the
-    // shallow result we are looking for -- that is, what specific impl.
-    let infcx = tcx
-        .infer_ctxt()
-        .ignoring_regions()
-        .with_opaque_type_inference(DefiningAnchor::Bubble)
-        .build();
-    //~^ HACK `Bubble` is required for
-    // this test to pass: type-alias-impl-trait/assoc-projection-ice.rs
-    let mut selcx = SelectionContext::new(&infcx);
-
-    let obligation_cause = ObligationCause::dummy();
-    let obligation = Obligation::new(tcx, obligation_cause, param_env, trait_ref);
-
-    let selection = match selcx.select(&obligation) {
-        Ok(Some(selection)) => selection,
-        Ok(None) => return Err(CodegenObligationError::Ambiguity),
-        Err(Unimplemented) => return Err(CodegenObligationError::Unimplemented),
-        Err(e) => {
-            bug!("Encountered error `{:?}` selecting `{:?}` during codegen", e, trait_ref)
-        }
-    };
-
-    debug!(?selection);
-
-    // Currently, we use a fulfillment context to completely resolve
-    // all nested obligations. This is because they can inform the
-    // inference of the impl's type parameters.
-    let mut fulfill_cx = <dyn TraitEngine<'tcx>>::new(tcx);
-    let impl_source = selection.map(|predicate| {
-        fulfill_cx.register_predicate_obligation(&infcx, predicate);
-    });
-
-    // In principle, we only need to do this so long as `impl_source`
-    // contains unbound type parameters. It could be a slight
-    // optimization to stop iterating early.
-    let errors = fulfill_cx.select_all_or_error(&infcx);
-    if !errors.is_empty() {
-        // `rustc_monomorphize::collector` assumes there are no type errors.
-        // Cycle errors are the only post-monomorphization errors possible; emit them now so
-        // `rustc_ty_utils::resolve_associated_item` doesn't return `None` post-monomorphization.
-        for err in errors {
-            if let FulfillmentErrorCode::CodeCycle(cycle) = err.code {
-                infcx.err_ctxt().report_overflow_error_cycle(&cycle);
-            }
-        }
-        return Err(CodegenObligationError::FulfillmentError);
-    }
-
-    let impl_source = infcx.resolve_vars_if_possible(impl_source);
-    let impl_source = infcx.tcx.erase_regions(impl_source);
-
-    // Opaque types may have gotten their hidden types constrained, but we can ignore them safely
-    // as they will get constrained elsewhere, too.
-    // (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();
-
-    Ok(&*tcx.arena.alloc(impl_source))
-}
index 99724fb28db1104ab90a8c7c04a6f54865d9377c..899e30275a05296eb2de1958b29b41286f3f51d0 100644 (file)
@@ -11,8 +11,8 @@
 use crate::traits::util::impl_subject_and_oblig;
 use crate::traits::SkipLeakCheck;
 use crate::traits::{
-    self, Normalized, Obligation, ObligationCause, ObligationCtxt, PredicateObligation,
-    PredicateObligations, SelectionContext,
+    self, Obligation, ObligationCause, ObligationCtxt, PredicateObligation, PredicateObligations,
+    SelectionContext,
 };
 use rustc_data_structures::fx::FxIndexSet;
 use rustc_errors::Diagnostic;
@@ -30,6 +30,8 @@
 use std::iter;
 use std::ops::ControlFlow;
 
+use super::NormalizeExt;
+
 /// Whether we do the orphan check relative to this crate or
 /// to some remote crate.
 #[derive(Copy, Clone, Debug)]
@@ -128,8 +130,8 @@ fn with_fresh_ty_vars<'cx, 'tcx>(
         predicates: tcx.predicates_of(impl_def_id).instantiate(tcx, impl_substs).predicates,
     };
 
-    let Normalized { value: mut header, obligations } =
-        traits::normalize(selcx, param_env, ObligationCause::dummy(), header);
+    let InferOk { value: mut header, obligations } =
+        selcx.infcx.at(&ObligationCause::dummy(), param_env).normalize(header);
 
     header.predicates.extend(obligations.into_iter().map(|o| o.predicate));
     header
index e9e65336299e45770425b46122890cd0cc75f0bf..7c9fde27420bc2b12ba79a6d08083b507dc2b8ec 100644 (file)
 #[instrument(skip(infcx), level = "debug")]
 pub fn is_const_evaluatable<'tcx>(
     infcx: &InferCtxt<'tcx>,
-    ct: ty::Const<'tcx>,
+    unexpanded_ct: ty::Const<'tcx>,
     param_env: ty::ParamEnv<'tcx>,
     span: Span,
 ) -> Result<(), NotConstEvaluatable> {
     let tcx = infcx.tcx;
-    let uv = match ct.kind() {
-        ty::ConstKind::Unevaluated(uv) => uv,
-        // FIXME(generic_const_exprs): this seems wrong but I couldn't find a way to get this to trigger
-        ty::ConstKind::Expr(_) => bug!("unexpected expr in `is_const_evaluatable: {ct:?}"),
+    match tcx.expand_abstract_consts(unexpanded_ct).kind() {
+        ty::ConstKind::Unevaluated(_) | ty::ConstKind::Expr(_) => (),
         ty::ConstKind::Param(_)
         | ty::ConstKind::Bound(_, _)
         | ty::ConstKind::Placeholder(_)
@@ -43,7 +41,7 @@ pub fn is_const_evaluatable<'tcx>(
     };
 
     if tcx.features().generic_const_exprs {
-        let ct = tcx.expand_abstract_consts(ct);
+        let ct = tcx.expand_abstract_consts(unexpanded_ct);
 
         let is_anon_ct = if let ty::ConstKind::Unevaluated(uv) = ct.kind() {
             tcx.def_kind(uv.def.did) == DefKind::AnonConst
@@ -62,18 +60,40 @@ pub fn is_const_evaluatable<'tcx>(
             }
         }
 
-        let concrete = infcx.const_eval_resolve(param_env, uv, Some(span));
-        match concrete {
-            Err(ErrorHandled::TooGeneric) => Err(NotConstEvaluatable::Error(
-                infcx
-                    .tcx
-                    .sess
-                    .delay_span_bug(span, "Missing value for constant, but no error reported?"),
-            )),
-            Err(ErrorHandled::Reported(e)) => Err(NotConstEvaluatable::Error(e)),
-            Ok(_) => Ok(()),
+        match unexpanded_ct.kind() {
+            ty::ConstKind::Expr(_) => {
+                // FIXME(generic_const_exprs): we have a `ConstKind::Expr` which is fully concrete, but
+                // currently it is not possible to evaluate `ConstKind::Expr` so we are unable to tell if it
+                // is evaluatable or not. For now we just ICE until this is implemented.
+                Err(NotConstEvaluatable::Error(tcx.sess.delay_span_bug(
+                    span,
+                    "evaluating `ConstKind::Expr` is not currently supported",
+                )))
+            }
+            ty::ConstKind::Unevaluated(uv) => {
+                let concrete = infcx.const_eval_resolve(param_env, uv, Some(span));
+                match concrete {
+                    Err(ErrorHandled::TooGeneric) => {
+                        Err(NotConstEvaluatable::Error(infcx.tcx.sess.delay_span_bug(
+                            span,
+                            "Missing value for constant, but no error reported?",
+                        )))
+                    }
+                    Err(ErrorHandled::Reported(e)) => Err(NotConstEvaluatable::Error(e)),
+                    Ok(_) => Ok(()),
+                }
+            }
+            _ => bug!("unexpected constkind in `is_const_evalautable: {unexpanded_ct:?}`"),
         }
     } else {
+        let uv = match unexpanded_ct.kind() {
+            ty::ConstKind::Unevaluated(uv) => uv,
+            ty::ConstKind::Expr(_) => {
+                bug!("`ConstKind::Expr` without `feature(generic_const_exprs)` enabled")
+            }
+            _ => bug!("unexpected constkind in `is_const_evalautable: {unexpanded_ct:?}`"),
+        };
+
         // FIXME: We should only try to evaluate a given constant here if it is fully concrete
         // as we don't want to allow things like `[u8; std::mem::size_of::<*mut T>()]`.
         //
@@ -92,7 +112,7 @@ pub fn is_const_evaluatable<'tcx>(
                     && satisfied_from_param_env(
                         tcx,
                         infcx,
-                        tcx.expand_abstract_consts(ct),
+                        tcx.expand_abstract_consts(unexpanded_ct),
                         param_env,
                     ) =>
             {
@@ -152,6 +172,7 @@ struct Visitor<'a, 'tcx> {
     impl<'a, 'tcx> TypeVisitor<'tcx> for Visitor<'a, 'tcx> {
         type BreakTy = ();
         fn visit_const(&mut self, c: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
+            debug!("is_const_evaluatable: candidate={:?}", c);
             if let Ok(()) = self.infcx.commit_if_ok(|_| {
                 let ocx = ObligationCtxt::new_in_snapshot(self.infcx);
                 if let Ok(()) = ocx.eq(&ObligationCause::dummy(), self.param_env, c.ty(), self.ct.ty())
@@ -187,7 +208,7 @@ fn visit_const(&mut self, c: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
                 let result = b_ct.visit_with(&mut v);
 
                 if let ControlFlow::Break(()) = result {
-                    debug!("is_const_evaluatable: abstract_const ~~> ok");
+                    debug!("is_const_evaluatable: yes");
                     return true;
                 }
             }
@@ -195,5 +216,6 @@ fn visit_const(&mut self, c: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
         }
     }
 
+    debug!("is_const_evaluatable: no");
     false
 }
index 64d01ddb09a493bafff61f309e741d0709af66e6..c028e89e4ea2963f093b48240a8f98ca613199d3 100644 (file)
@@ -112,6 +112,24 @@ pub fn normalize<T: TypeFoldable<'tcx>>(
         self.register_infer_ok_obligations(infer_ok)
     }
 
+    /// Makes `expected <: actual`.
+    pub fn eq_exp<T>(
+        &self,
+        cause: &ObligationCause<'tcx>,
+        param_env: ty::ParamEnv<'tcx>,
+        a_is_expected: bool,
+        a: T,
+        b: T,
+    ) -> Result<(), TypeError<'tcx>>
+    where
+        T: ToTrace<'tcx>,
+    {
+        self.infcx
+            .at(cause, param_env)
+            .eq_exp(a_is_expected, a, b)
+            .map(|infer_ok| self.register_infer_ok_obligations(infer_ok))
+    }
+
     pub fn eq<T: ToTrace<'tcx>>(
         &self,
         cause: &ObligationCause<'tcx>,
index 049b24b39975dd3ff7e21978d667a4d40d324ee1..82449a36b1d54115320fbc52c17d5f7ebdcdf5de 100644 (file)
@@ -9,7 +9,7 @@
 };
 use crate::infer::error_reporting::{TyCategory, TypeAnnotationNeeded as ErrorCode};
 use crate::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
-use crate::infer::{self, InferCtxt, TyCtxtInferExt};
+use crate::infer::{self, InferCtxt};
 use crate::traits::query::evaluate_obligation::InferCtxtExt as _;
 use crate::traits::query::normalize::QueryNormalizeExt as _;
 use crate::traits::specialize::to_pretty_impl_header;
@@ -71,7 +71,7 @@ pub trait InferCtxtExt<'tcx> {
     /// returns a span and `ArgKind` information that describes the
     /// arguments it expects. This can be supplied to
     /// `report_arg_count_mismatch`.
-    fn get_fn_like_arguments(&self, node: Node<'_>) -> Option<(Span, Vec<ArgKind>)>;
+    fn get_fn_like_arguments(&self, node: Node<'_>) -> Option<(Span, Option<Span>, Vec<ArgKind>)>;
 
     /// Reports an error when the number of arguments needed by a
     /// trait match doesn't match the number that the expression
@@ -83,6 +83,7 @@ fn report_arg_count_mismatch(
         expected_args: Vec<ArgKind>,
         found_args: Vec<ArgKind>,
         is_closure: bool,
+        closure_pipe_span: Option<Span>,
     ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed>;
 
     /// Checks if the type implements one of `Fn`, `FnMut`, or `FnOnce`
@@ -98,26 +99,36 @@ fn type_implements_fn_trait(
 }
 
 pub trait TypeErrCtxtExt<'tcx> {
+    fn report_overflow_error<T>(
+        &self,
+        predicate: &T,
+        span: Span,
+        suggest_increasing_limit: bool,
+        mutate: impl FnOnce(&mut Diagnostic),
+    ) -> !
+    where
+        T: fmt::Display
+            + TypeFoldable<'tcx>
+            + Print<'tcx, FmtPrinter<'tcx, 'tcx>, Output = FmtPrinter<'tcx, 'tcx>>,
+        <T as Print<'tcx, FmtPrinter<'tcx, 'tcx>>>::Error: std::fmt::Debug;
+
     fn report_fulfillment_errors(
         &self,
         errors: &[FulfillmentError<'tcx>],
         body_id: Option<hir::BodyId>,
     ) -> ErrorGuaranteed;
 
-    fn report_overflow_error<T>(
+    fn report_overflow_obligation<T>(
         &self,
         obligation: &Obligation<'tcx, T>,
         suggest_increasing_limit: bool,
     ) -> !
     where
-        T: fmt::Display
-            + TypeFoldable<'tcx>
-            + Print<'tcx, FmtPrinter<'tcx, 'tcx>, Output = FmtPrinter<'tcx, 'tcx>>,
-        <T as Print<'tcx, FmtPrinter<'tcx, 'tcx>>>::Error: std::fmt::Debug;
+        T: ToPredicate<'tcx> + Clone;
 
     fn suggest_new_overflow_limit(&self, err: &mut Diagnostic);
 
-    fn report_overflow_error_cycle(&self, cycle: &[PredicateObligation<'tcx>]) -> !;
+    fn report_overflow_obligation_cycle(&self, cycle: &[PredicateObligation<'tcx>]) -> !;
 
     /// The `root_obligation` parameter should be the `root_obligation` field
     /// from a `FulfillmentError`. If no `FulfillmentError` is available,
@@ -135,15 +146,16 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> {
     /// returns a span and `ArgKind` information that describes the
     /// arguments it expects. This can be supplied to
     /// `report_arg_count_mismatch`.
-    fn get_fn_like_arguments(&self, node: Node<'_>) -> Option<(Span, Vec<ArgKind>)> {
+    fn get_fn_like_arguments(&self, node: Node<'_>) -> Option<(Span, Option<Span>, Vec<ArgKind>)> {
         let sm = self.tcx.sess.source_map();
         let hir = self.tcx.hir();
         Some(match node {
             Node::Expr(&hir::Expr {
-                kind: hir::ExprKind::Closure(&hir::Closure { body, fn_decl_span, .. }),
+                kind: hir::ExprKind::Closure(&hir::Closure { body, fn_decl_span, fn_arg_span, .. }),
                 ..
             }) => (
                 fn_decl_span,
+                fn_arg_span,
                 hir.body(body)
                     .params
                     .iter()
@@ -174,6 +186,7 @@ fn get_fn_like_arguments(&self, node: Node<'_>) -> Option<(Span, Vec<ArgKind>)>
                 kind: hir::TraitItemKind::Fn(ref sig, _), ..
             }) => (
                 sig.span,
+                None,
                 sig.decl
                     .inputs
                     .iter()
@@ -188,7 +201,7 @@ fn get_fn_like_arguments(&self, node: Node<'_>) -> Option<(Span, Vec<ArgKind>)>
             ),
             Node::Ctor(ref variant_data) => {
                 let span = variant_data.ctor_hir_id().map_or(DUMMY_SP, |id| hir.span(id));
-                (span, vec![ArgKind::empty(); variant_data.fields().len()])
+                (span, None, vec![ArgKind::empty(); variant_data.fields().len()])
             }
             _ => panic!("non-FnLike node found: {:?}", node),
         })
@@ -204,6 +217,7 @@ fn report_arg_count_mismatch(
         expected_args: Vec<ArgKind>,
         found_args: Vec<ArgKind>,
         is_closure: bool,
+        closure_arg_span: Option<Span>,
     ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
         let kind = if is_closure { "closure" } else { "function" };
 
@@ -241,24 +255,13 @@ fn report_arg_count_mismatch(
         if let Some(found_span) = found_span {
             err.span_label(found_span, format!("takes {}", found_str));
 
-            // move |_| { ... }
-            // ^^^^^^^^-- def_span
-            //
-            // move |_| { ... }
-            // ^^^^^-- prefix
-            let prefix_span = self.tcx.sess.source_map().span_until_non_whitespace(found_span);
-            // move |_| { ... }
-            //      ^^^-- pipe_span
-            let pipe_span =
-                if let Some(span) = found_span.trim_start(prefix_span) { span } else { found_span };
-
             // Suggest to take and ignore the arguments with expected_args_length `_`s if
             // found arguments is empty (assume the user just wants to ignore args in this case).
             // For example, if `expected_args_length` is 2, suggest `|_, _|`.
             if found_args.is_empty() && is_closure {
                 let underscores = vec!["_"; expected_args.len()].join(", ");
                 err.span_suggestion_verbose(
-                    pipe_span,
+                    closure_arg_span.unwrap_or(found_span),
                     &format!(
                         "consider changing the closure to take and ignore the expected argument{}",
                         pluralize!(expected_args.len())
@@ -465,8 +468,10 @@ struct ErrorDescriptor<'tcx> {
     /// occurrences in any case.
     fn report_overflow_error<T>(
         &self,
-        obligation: &Obligation<'tcx, T>,
+        predicate: &T,
+        span: Span,
         suggest_increasing_limit: bool,
+        mutate: impl FnOnce(&mut Diagnostic),
     ) -> !
     where
         T: fmt::Display
@@ -474,8 +479,9 @@ fn report_overflow_error<T>(
             + Print<'tcx, FmtPrinter<'tcx, 'tcx>, Output = FmtPrinter<'tcx, 'tcx>>,
         <T as Print<'tcx, FmtPrinter<'tcx, 'tcx>>>::Error: std::fmt::Debug,
     {
-        let predicate = self.resolve_vars_if_possible(obligation.predicate.clone());
+        let predicate = self.resolve_vars_if_possible(predicate.clone());
         let mut pred_str = predicate.to_string();
+
         if pred_str.len() > 50 {
             // We don't need to save the type to a file, we will be talking about this type already
             // in a separate note when we explain the obligation, so it will be available that way.
@@ -490,7 +496,7 @@ fn report_overflow_error<T>(
         }
         let mut err = struct_span_err!(
             self.tcx.sess,
-            obligation.cause.span,
+            span,
             E0275,
             "overflow evaluating the requirement `{}`",
             pred_str,
@@ -500,20 +506,46 @@ fn report_overflow_error<T>(
             self.suggest_new_overflow_limit(&mut err);
         }
 
-        self.note_obligation_cause_code(
-            &mut err,
-            &obligation.predicate,
-            obligation.param_env,
-            obligation.cause.code(),
-            &mut vec![],
-            &mut Default::default(),
-        );
+        mutate(&mut err);
 
         err.emit();
         self.tcx.sess.abort_if_errors();
         bug!();
     }
 
+    /// Reports that an overflow has occurred and halts compilation. We
+    /// halt compilation unconditionally because it is important that
+    /// overflows never be masked -- they basically represent computations
+    /// whose result could not be truly determined and thus we can't say
+    /// if the program type checks or not -- and they are unusual
+    /// occurrences in any case.
+    fn report_overflow_obligation<T>(
+        &self,
+        obligation: &Obligation<'tcx, T>,
+        suggest_increasing_limit: bool,
+    ) -> !
+    where
+        T: ToPredicate<'tcx> + Clone,
+    {
+        let predicate = obligation.predicate.clone().to_predicate(self.tcx);
+        let predicate = self.resolve_vars_if_possible(predicate);
+        self.report_overflow_error(
+            &predicate,
+            obligation.cause.span,
+            suggest_increasing_limit,
+            |err| {
+                self.note_obligation_cause_code(
+                    err,
+                    &predicate,
+                    obligation.param_env,
+                    obligation.cause.code(),
+                    &mut vec![],
+                    &mut Default::default(),
+                );
+            },
+        );
+    }
+
     fn suggest_new_overflow_limit(&self, err: &mut Diagnostic) {
         let suggested_limit = match self.tcx.recursion_limit() {
             Limit(0) => Limit(2),
@@ -528,11 +560,11 @@ fn suggest_new_overflow_limit(&self, err: &mut Diagnostic) {
     }
 
     /// Reports that a cycle was detected which led to overflow and halts
-    /// compilation. This is equivalent to `report_overflow_error` except
+    /// compilation. This is equivalent to `report_overflow_obligation` except
     /// that we can give a more helpful error message (and, in particular,
     /// we do not suggest increasing the overflow limit, which is not
     /// going to help).
-    fn report_overflow_error_cycle(&self, cycle: &[PredicateObligation<'tcx>]) -> ! {
+    fn report_overflow_obligation_cycle(&self, cycle: &[PredicateObligation<'tcx>]) -> ! {
         let cycle = self.resolve_vars_if_possible(cycle.to_owned());
         assert!(!cycle.is_empty());
 
@@ -540,7 +572,10 @@ fn report_overflow_error_cycle(&self, cycle: &[PredicateObligation<'tcx>]) -> !
 
         // The 'deepest' obligation is most likely to have a useful
         // cause 'backtrace'
-        self.report_overflow_error(cycle.iter().max_by_key(|p| p.recursion_depth).unwrap(), false);
+        self.report_overflow_obligation(
+            cycle.iter().max_by_key(|p| p.recursion_depth).unwrap(),
+            false,
+        );
     }
 
     fn report_selection_error(
@@ -562,6 +597,7 @@ fn report_selection_error(
                 // can get a better error message by performing HIR-based well-formedness checking.
                 if let ObligationCauseCode::WellFormed(Some(wf_loc)) =
                     root_obligation.cause.code().peel_derives()
+                    && !obligation.predicate.has_non_region_infer()
                 {
                     if let Some(cause) = self
                         .tcx
@@ -1252,13 +1288,14 @@ fn report_selection_error(
                         obligation.cause.code(),
                     )
                 } else {
-                    let (closure_span, found) = found_did
+                    let (closure_span, closure_arg_span, found) = found_did
                         .and_then(|did| {
                             let node = self.tcx.hir().get_if_local(did)?;
-                            let (found_span, found) = self.get_fn_like_arguments(node)?;
-                            Some((Some(found_span), found))
+                            let (found_span, closure_arg_span, found) =
+                                self.get_fn_like_arguments(node)?;
+                            Some((Some(found_span), closure_arg_span, found))
                         })
-                        .unwrap_or((found_span, found));
+                        .unwrap_or((found_span, None, found));
 
                     self.report_arg_count_mismatch(
                         span,
@@ -1266,6 +1303,7 @@ fn report_selection_error(
                         expected,
                         found,
                         found_trait_ty.is_closure(),
+                        closure_arg_span,
                     )
                 }
             }
@@ -1559,7 +1597,7 @@ fn report_fulfillment_error(
                 diag.emit();
             }
             FulfillmentErrorCode::CodeCycle(ref cycle) => {
-                self.report_overflow_error_cycle(cycle);
+                self.report_overflow_obligation_cycle(cycle);
             }
         }
     }
@@ -1577,32 +1615,26 @@ fn report_projection_error(
         }
 
         self.probe(|_| {
-            let mut err = error.err;
-            let mut values = None;
+            let ocx = ObligationCtxt::new_in_snapshot(self);
 
             // try to find the mismatched types to report the error with.
             //
             // this can fail if the problem was higher-ranked, in which
             // cause I have no idea for a good error message.
             let bound_predicate = predicate.kind();
-            if let ty::PredicateKind::Clause(ty::Clause::Projection(data)) =
+            let (values, err) = if let ty::PredicateKind::Clause(ty::Clause::Projection(data)) =
                 bound_predicate.skip_binder()
             {
-                let mut selcx = SelectionContext::new(self);
                 let data = self.replace_bound_vars_with_fresh_vars(
                     obligation.cause.span,
                     infer::LateBoundRegionConversionTime::HigherRankedType,
                     bound_predicate.rebind(data),
                 );
-                let mut obligations = vec![];
-                // FIXME(normalization): Change this to use `At::normalize`
-                let normalized_ty = super::normalize_projection_type(
-                    &mut selcx,
+                let normalized_ty = ocx.normalize(
+                    &obligation.cause,
                     obligation.param_env,
-                    data.projection_ty,
-                    obligation.cause.clone(),
-                    0,
-                    &mut obligations,
+                    self.tcx
+                        .mk_projection(data.projection_ty.item_def_id, data.projection_ty.substs),
                 );
 
                 debug!(?obligation.cause, ?obligation.param_env);
@@ -1618,19 +1650,34 @@ fn report_projection_error(
                         | ObligationCauseCode::ObjectCastObligation(..)
                         | ObligationCauseCode::OpaqueType
                 );
-                if let Err(new_err) = self.at(&obligation.cause, obligation.param_env).eq_exp(
+                let expected_ty = data.term.ty().unwrap_or_else(|| self.tcx.ty_error());
+
+                // constrain inference variables a bit more to nested obligations from normalize so
+                // we can have more helpful errors.
+                ocx.select_where_possible();
+
+                if let Err(new_err) = ocx.eq_exp(
+                    &obligation.cause,
+                    obligation.param_env,
                     is_normalized_ty_expected,
                     normalized_ty,
-                    data.term,
+                    expected_ty,
                 ) {
-                    values = Some((data, is_normalized_ty_expected, normalized_ty, data.term));
-                    err = new_err;
+                    (Some((data, is_normalized_ty_expected, normalized_ty, expected_ty)), new_err)
+                } else {
+                    (None, error.err)
                 }
-            }
+            } else {
+                (None, error.err)
+            };
 
             let msg = values
                 .and_then(|(predicate, _, normalized_ty, expected_ty)| {
-                    self.maybe_detailed_projection_msg(predicate, normalized_ty, expected_ty)
+                    self.maybe_detailed_projection_msg(
+                        predicate,
+                        normalized_ty.into(),
+                        expected_ty.into(),
+                    )
                 })
                 .unwrap_or_else(|| format!("type mismatch resolving `{}`", predicate));
             let mut diag = struct_span_err!(self.tcx.sess, obligation.cause.span, E0271, "{msg}");
@@ -1672,11 +1719,11 @@ fn report_projection_error(
                 &mut diag,
                 &obligation.cause,
                 secondary_span,
-                values.map(|(_, is_normalized_ty_expected, normalized_ty, term)| {
+                values.map(|(_, is_normalized_ty_expected, normalized_ty, expected_ty)| {
                     infer::ValuePairs::Terms(ExpectedFound::new(
                         is_normalized_ty_expected,
-                        normalized_ty,
-                        term,
+                        normalized_ty.into(),
+                        expected_ty.into(),
                     ))
                 }),
                 err,
@@ -1806,7 +1853,8 @@ fn find_similar_impl_candidates(
         &self,
         trait_pred: ty::PolyTraitPredicate<'tcx>,
     ) -> Vec<ImplCandidate<'tcx>> {
-        self.tcx
+        let mut candidates: Vec<_> = self
+            .tcx
             .all_impls(trait_pred.def_id())
             .filter_map(|def_id| {
                 if self.tcx.impl_polarity(def_id) == ty::ImplPolarity::Negative
@@ -1822,7 +1870,14 @@ fn find_similar_impl_candidates(
                 self.fuzzy_match_tys(trait_pred.skip_binder().self_ty(), imp.self_ty(), false)
                     .map(|similarity| ImplCandidate { trait_ref: imp, similarity })
             })
-            .collect()
+            .collect();
+        if candidates.iter().any(|c| matches!(c.similarity, CandidateSimilarity::Exact { .. })) {
+            // If any of the candidates is a perfect match, we don't want to show all of them.
+            // This is particularly relevant for the case of numeric types (as they all have the
+            // same cathegory).
+            candidates.retain(|c| matches!(c.similarity, CandidateSimilarity::Exact { .. }));
+        }
+        candidates
     }
 
     fn report_similar_impl_candidates(
@@ -1930,14 +1985,6 @@ fn report_similar_impl_candidates(
             return report(normalized_impl_candidates, err);
         }
 
-        let normalize = |candidate| {
-            let infcx = self.tcx.infer_ctxt().build();
-            infcx
-                .at(&ObligationCause::dummy(), ty::ParamEnv::empty())
-                .query_normalize(candidate)
-                .map_or(candidate, |normalized| normalized.value)
-        };
-
         // Sort impl candidates so that ordering is consistent for UI tests.
         // because the ordering of `impl_candidates` may not be deterministic:
         // https://github.com/rust-lang/rust/pull/57475#issuecomment-455519507
@@ -1947,7 +1994,11 @@ fn report_similar_impl_candidates(
         let mut normalized_impl_candidates_and_similarities = impl_candidates
             .into_iter()
             .map(|ImplCandidate { trait_ref, similarity }| {
-                let normalized = normalize(trait_ref);
+                // FIXME(compiler-errors): This should be using `NormalizeExt::normalize`
+                let normalized = self
+                    .at(&ObligationCause::dummy(), ty::ParamEnv::empty())
+                    .query_normalize(trait_ref)
+                    .map_or(trait_ref, |normalized| normalized.value);
                 (similarity, normalized)
             })
             .collect::<Vec<_>>();
index 1740128727a5a34bf1ff8847a1dcdfa0fcd56f75..9f5814a6bda738c7e275c6f2a7d935c0e87a5d9e 100644 (file)
@@ -36,7 +36,7 @@
 use super::InferCtxtPrivExt;
 use crate::infer::InferCtxtExt as _;
 use crate::traits::query::evaluate_obligation::InferCtxtExt as _;
-use rustc_middle::ty::print::with_no_trimmed_paths;
+use rustc_middle::ty::print::{with_forced_trimmed_paths, with_no_trimmed_paths};
 
 #[derive(Debug)]
 pub enum GeneratorInteriorOrUpvar {
@@ -298,7 +298,7 @@ fn note_obligation_cause_code<T>(
         obligated_types: &mut Vec<Ty<'tcx>>,
         seen_requirements: &mut FxHashSet<DefId>,
     ) where
-        T: fmt::Display + ToPredicate<'tcx, T>;
+        T: fmt::Display + ToPredicate<'tcx>;
 
     /// Suggest to await before try: future? => future.await?
     fn suggest_await_before_try(
@@ -2353,7 +2353,7 @@ fn note_obligation_cause_code<T>(
         obligated_types: &mut Vec<Ty<'tcx>>,
         seen_requirements: &mut FxHashSet<DefId>,
     ) where
-        T: fmt::Display,
+        T: fmt::Display + ToPredicate<'tcx>,
     {
         let tcx = self.tcx;
         match *cause_code {
@@ -2412,21 +2412,22 @@ fn note_obligation_cause_code<T>(
             ObligationCauseCode::BindingObligation(item_def_id, span)
             | ObligationCauseCode::ExprBindingObligation(item_def_id, span, ..) => {
                 let item_name = tcx.def_path_str(item_def_id);
+                let short_item_name = with_forced_trimmed_paths!(tcx.def_path_str(item_def_id));
                 let mut multispan = MultiSpan::from(span);
+                let sm = tcx.sess.source_map();
                 if let Some(ident) = tcx.opt_item_ident(item_def_id) {
-                    let sm = tcx.sess.source_map();
                     let same_line =
                         match (sm.lookup_line(ident.span.hi()), sm.lookup_line(span.lo())) {
                             (Ok(l), Ok(r)) => l.line == r.line,
                             _ => true,
                         };
-                    if !ident.span.is_dummy() && !ident.span.overlaps(span) && !same_line {
+                    if ident.span.is_visible(sm) && !ident.span.overlaps(span) && !same_line {
                         multispan.push_span_label(ident.span, "required by a bound in this");
                     }
                 }
-                let descr = format!("required by a bound in `{}`", item_name);
-                if !span.is_dummy() {
-                    let msg = format!("required by this bound in `{}`", item_name);
+                let descr = format!("required by a bound in `{item_name}`");
+                if span.is_visible(sm) {
+                    let msg = format!("required by this bound in `{short_item_name}`");
                     multispan.push_span_label(span, msg);
                     err.span_note(multispan, &descr);
                 } else {
index 371367f0deb3e671f956c7dd41d898f4e5eaf83b..ea4bf42c515b5fb5a7aa83413b4d3eca80236736 100644 (file)
@@ -4,7 +4,6 @@
 
 pub mod auto_trait;
 mod chalk_fulfill;
-pub mod codegen;
 mod coherence;
 pub mod const_evaluatable;
 mod engine;
@@ -20,9 +19,9 @@
 mod specialize;
 mod structural_match;
 mod util;
+mod vtable;
 pub mod wf;
 
-use crate::errors::DumpVTableEntries;
 use crate::infer::outlives::env::OutlivesEnvironment;
 use crate::infer::{InferCtxt, TyCtxtInferExt};
 use crate::traits::error_reporting::TypeErrCtxtExt as _;
 use rustc_errors::ErrorGuaranteed;
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
-use rustc_hir::lang_items::LangItem;
 use rustc_middle::ty::fold::TypeFoldable;
 use rustc_middle::ty::visit::TypeVisitable;
-use rustc_middle::ty::{
-    self, DefIdTree, GenericParamDefKind, ToPredicate, Ty, TyCtxt, TypeSuperVisitable, VtblEntry,
-};
+use rustc_middle::ty::{self, DefIdTree, ToPredicate, Ty, TyCtxt, TypeSuperVisitable};
 use rustc_middle::ty::{InternalSubsts, SubstsRef};
-use rustc_span::{sym, Span};
-use smallvec::SmallVec;
+use rustc_span::Span;
 
 use std::fmt::Debug;
 use std::ops::ControlFlow;
@@ -56,7 +51,6 @@
 pub use self::object_safety::is_vtable_safe_method;
 pub use self::object_safety::MethodViolationCode;
 pub use self::object_safety::ObjectSafetyViolation;
-pub(crate) use self::project::{normalize, normalize_to};
 pub use self::project::{normalize_projection_type, NormalizeExt};
 pub use self::select::{EvaluationCache, SelectionCache, SelectionContext};
 pub use self::select::{EvaluationResult, IntercrateAmbiguityCause, OverflowError};
@@ -151,7 +145,7 @@ pub fn type_known_to_meet_bound_modulo_regions<'tcx>(
 fn pred_known_to_hold_modulo_regions<'tcx>(
     infcx: &InferCtxt<'tcx>,
     param_env: ty::ParamEnv<'tcx>,
-    pred: impl ToPredicate<'tcx, ty::Predicate<'tcx>> + TypeVisitable<'tcx>,
+    pred: impl ToPredicate<'tcx> + TypeVisitable<'tcx>,
     span: Span,
 ) -> bool {
     let has_non_region_infer = pred.has_non_region_infer();
@@ -568,369 +562,12 @@ fn visit_const(&mut self, ct: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
     false
 }
 
-#[derive(Clone, Debug)]
-enum VtblSegment<'tcx> {
-    MetadataDSA,
-    TraitOwnEntries { trait_ref: ty::PolyTraitRef<'tcx>, emit_vptr: bool },
-}
-
-/// Prepare the segments for a vtable
-fn prepare_vtable_segments<'tcx, T>(
-    tcx: TyCtxt<'tcx>,
-    trait_ref: ty::PolyTraitRef<'tcx>,
-    mut segment_visitor: impl FnMut(VtblSegment<'tcx>) -> ControlFlow<T>,
-) -> Option<T> {
-    // The following constraints holds for the final arrangement.
-    // 1. The whole virtual table of the first direct super trait is included as the
-    //    the prefix. If this trait doesn't have any super traits, then this step
-    //    consists of the dsa metadata.
-    // 2. Then comes the proper pointer metadata(vptr) and all own methods for all
-    //    other super traits except those already included as part of the first
-    //    direct super trait virtual table.
-    // 3. finally, the own methods of this trait.
-
-    // This has the advantage that trait upcasting to the first direct super trait on each level
-    // is zero cost, and to another trait includes only replacing the pointer with one level indirection,
-    // while not using too much extra memory.
-
-    // For a single inheritance relationship like this,
-    //   D --> C --> B --> A
-    // The resulting vtable will consists of these segments:
-    //  DSA, A, B, C, D
-
-    // For a multiple inheritance relationship like this,
-    //   D --> C --> A
-    //           \-> B
-    // The resulting vtable will consists of these segments:
-    //  DSA, A, B, B-vptr, C, D
-
-    // For a diamond inheritance relationship like this,
-    //   D --> B --> A
-    //     \-> C -/
-    // The resulting vtable will consists of these segments:
-    //  DSA, A, B, C, C-vptr, D
-
-    // For a more complex inheritance relationship like this:
-    //   O --> G --> C --> A
-    //     \     \     \-> B
-    //     |     |-> F --> D
-    //     |           \-> E
-    //     |-> N --> J --> H
-    //           \     \-> I
-    //           |-> M --> K
-    //                 \-> L
-    // The resulting vtable will consists of these segments:
-    //  DSA, A, B, B-vptr, C, D, D-vptr, E, E-vptr, F, F-vptr, G,
-    //  H, H-vptr, I, I-vptr, J, J-vptr, K, K-vptr, L, L-vptr, M, M-vptr,
-    //  N, N-vptr, O
-
-    // emit dsa segment first.
-    if let ControlFlow::Break(v) = (segment_visitor)(VtblSegment::MetadataDSA) {
-        return Some(v);
-    }
-
-    let mut emit_vptr_on_new_entry = false;
-    let mut visited = util::PredicateSet::new(tcx);
-    let predicate = trait_ref.without_const().to_predicate(tcx);
-    let mut stack: SmallVec<[(ty::PolyTraitRef<'tcx>, _, _); 5]> =
-        smallvec![(trait_ref, emit_vptr_on_new_entry, None)];
-    visited.insert(predicate);
-
-    // the main traversal loop:
-    // basically we want to cut the inheritance directed graph into a few non-overlapping slices of nodes
-    // that each node is emitted after all its descendents have been emitted.
-    // so we convert the directed graph into a tree by skipping all previously visited nodes using a visited set.
-    // this is done on the fly.
-    // Each loop run emits a slice - it starts by find a "childless" unvisited node, backtracking upwards, and it
-    // stops after it finds a node that has a next-sibling node.
-    // This next-sibling node will used as the starting point of next slice.
-
-    // Example:
-    // For a diamond inheritance relationship like this,
-    //   D#1 --> B#0 --> A#0
-    //     \-> C#1 -/
-
-    // Starting point 0 stack [D]
-    // Loop run #0: Stack after diving in is [D B A], A is "childless"
-    // after this point, all newly visited nodes won't have a vtable that equals to a prefix of this one.
-    // Loop run #0: Emitting the slice [B A] (in reverse order), B has a next-sibling node, so this slice stops here.
-    // Loop run #0: Stack after exiting out is [D C], C is the next starting point.
-    // Loop run #1: Stack after diving in is [D C], C is "childless", since its child A is skipped(already emitted).
-    // Loop run #1: Emitting the slice [D C] (in reverse order). No one has a next-sibling node.
-    // Loop run #1: Stack after exiting out is []. Now the function exits.
-
-    loop {
-        // dive deeper into the stack, recording the path
-        'diving_in: loop {
-            if let Some((inner_most_trait_ref, _, _)) = stack.last() {
-                let inner_most_trait_ref = *inner_most_trait_ref;
-                let mut direct_super_traits_iter = tcx
-                    .super_predicates_of(inner_most_trait_ref.def_id())
-                    .predicates
-                    .into_iter()
-                    .filter_map(move |(pred, _)| {
-                        pred.subst_supertrait(tcx, &inner_most_trait_ref).to_opt_poly_trait_pred()
-                    });
-
-                'diving_in_skip_visited_traits: loop {
-                    if let Some(next_super_trait) = direct_super_traits_iter.next() {
-                        if visited.insert(next_super_trait.to_predicate(tcx)) {
-                            // We're throwing away potential constness of super traits here.
-                            // FIXME: handle ~const super traits
-                            let next_super_trait = next_super_trait.map_bound(|t| t.trait_ref);
-                            stack.push((
-                                next_super_trait,
-                                emit_vptr_on_new_entry,
-                                Some(direct_super_traits_iter),
-                            ));
-                            break 'diving_in_skip_visited_traits;
-                        } else {
-                            continue 'diving_in_skip_visited_traits;
-                        }
-                    } else {
-                        break 'diving_in;
-                    }
-                }
-            }
-        }
-
-        // Other than the left-most path, vptr should be emitted for each trait.
-        emit_vptr_on_new_entry = true;
-
-        // emit innermost item, move to next sibling and stop there if possible, otherwise jump to outer level.
-        'exiting_out: loop {
-            if let Some((inner_most_trait_ref, emit_vptr, siblings_opt)) = stack.last_mut() {
-                if let ControlFlow::Break(v) = (segment_visitor)(VtblSegment::TraitOwnEntries {
-                    trait_ref: *inner_most_trait_ref,
-                    emit_vptr: *emit_vptr,
-                }) {
-                    return Some(v);
-                }
-
-                'exiting_out_skip_visited_traits: loop {
-                    if let Some(siblings) = siblings_opt {
-                        if let Some(next_inner_most_trait_ref) = siblings.next() {
-                            if visited.insert(next_inner_most_trait_ref.to_predicate(tcx)) {
-                                // We're throwing away potential constness of super traits here.
-                                // FIXME: handle ~const super traits
-                                let next_inner_most_trait_ref =
-                                    next_inner_most_trait_ref.map_bound(|t| t.trait_ref);
-                                *inner_most_trait_ref = next_inner_most_trait_ref;
-                                *emit_vptr = emit_vptr_on_new_entry;
-                                break 'exiting_out;
-                            } else {
-                                continue 'exiting_out_skip_visited_traits;
-                            }
-                        }
-                    }
-                    stack.pop();
-                    continue 'exiting_out;
-                }
-            }
-            // all done
-            return None;
-        }
-    }
-}
-
-fn dump_vtable_entries<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    sp: Span,
-    trait_ref: ty::PolyTraitRef<'tcx>,
-    entries: &[VtblEntry<'tcx>],
-) {
-    tcx.sess.emit_err(DumpVTableEntries {
-        span: sp,
-        trait_ref,
-        entries: format!("{:#?}", entries),
-    });
-}
-
-fn own_existential_vtable_entries<'tcx>(tcx: TyCtxt<'tcx>, trait_def_id: DefId) -> &'tcx [DefId] {
-    let trait_methods = tcx
-        .associated_items(trait_def_id)
-        .in_definition_order()
-        .filter(|item| item.kind == ty::AssocKind::Fn);
-    // Now list each method's DefId (for within its trait).
-    let own_entries = trait_methods.filter_map(move |trait_method| {
-        debug!("own_existential_vtable_entry: trait_method={:?}", trait_method);
-        let def_id = trait_method.def_id;
-
-        // Some methods cannot be called on an object; skip those.
-        if !is_vtable_safe_method(tcx, trait_def_id, &trait_method) {
-            debug!("own_existential_vtable_entry: not vtable safe");
-            return None;
-        }
-
-        Some(def_id)
-    });
-
-    tcx.arena.alloc_from_iter(own_entries.into_iter())
-}
-
-/// Given a trait `trait_ref`, iterates the vtable entries
-/// that come from `trait_ref`, including its supertraits.
-fn vtable_entries<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    trait_ref: ty::PolyTraitRef<'tcx>,
-) -> &'tcx [VtblEntry<'tcx>] {
-    debug!("vtable_entries({:?})", trait_ref);
-
-    let mut entries = vec![];
-
-    let vtable_segment_callback = |segment| -> ControlFlow<()> {
-        match segment {
-            VtblSegment::MetadataDSA => {
-                entries.extend(TyCtxt::COMMON_VTABLE_ENTRIES);
-            }
-            VtblSegment::TraitOwnEntries { trait_ref, emit_vptr } => {
-                let existential_trait_ref = trait_ref
-                    .map_bound(|trait_ref| ty::ExistentialTraitRef::erase_self_ty(tcx, trait_ref));
-
-                // Lookup the shape of vtable for the trait.
-                let own_existential_entries =
-                    tcx.own_existential_vtable_entries(existential_trait_ref.def_id());
-
-                let own_entries = own_existential_entries.iter().copied().map(|def_id| {
-                    debug!("vtable_entries: trait_method={:?}", def_id);
-
-                    // The method may have some early-bound lifetimes; add regions for those.
-                    let substs = trait_ref.map_bound(|trait_ref| {
-                        InternalSubsts::for_item(tcx, def_id, |param, _| match param.kind {
-                            GenericParamDefKind::Lifetime => tcx.lifetimes.re_erased.into(),
-                            GenericParamDefKind::Type { .. }
-                            | GenericParamDefKind::Const { .. } => {
-                                trait_ref.substs[param.index as usize]
-                            }
-                        })
-                    });
-
-                    // The trait type may have higher-ranked lifetimes in it;
-                    // erase them if they appear, so that we get the type
-                    // at some particular call site.
-                    let substs = tcx
-                        .normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), substs);
-
-                    // It's possible that the method relies on where-clauses that
-                    // do not hold for this particular set of type parameters.
-                    // Note that this method could then never be called, so we
-                    // do not want to try and codegen it, in that case (see #23435).
-                    let predicates = tcx.predicates_of(def_id).instantiate_own(tcx, substs);
-                    if impossible_predicates(tcx, predicates.predicates) {
-                        debug!("vtable_entries: predicates do not hold");
-                        return VtblEntry::Vacant;
-                    }
-
-                    let instance = ty::Instance::resolve_for_vtable(
-                        tcx,
-                        ty::ParamEnv::reveal_all(),
-                        def_id,
-                        substs,
-                    )
-                    .expect("resolution failed during building vtable representation");
-                    VtblEntry::Method(instance)
-                });
-
-                entries.extend(own_entries);
-
-                if emit_vptr {
-                    entries.push(VtblEntry::TraitVPtr(trait_ref));
-                }
-            }
-        }
-
-        ControlFlow::Continue(())
-    };
-
-    let _ = prepare_vtable_segments(tcx, trait_ref, vtable_segment_callback);
-
-    if tcx.has_attr(trait_ref.def_id(), sym::rustc_dump_vtable) {
-        let sp = tcx.def_span(trait_ref.def_id());
-        dump_vtable_entries(tcx, sp, trait_ref, &entries);
-    }
-
-    tcx.arena.alloc_from_iter(entries.into_iter())
-}
-
-/// Find slot base for trait methods within vtable entries of another trait
-fn vtable_trait_first_method_offset<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    key: (
-        ty::PolyTraitRef<'tcx>, // trait_to_be_found
-        ty::PolyTraitRef<'tcx>, // trait_owning_vtable
-    ),
-) -> usize {
-    let (trait_to_be_found, trait_owning_vtable) = key;
-
-    // #90177
-    let trait_to_be_found_erased = tcx.erase_regions(trait_to_be_found);
-
-    let vtable_segment_callback = {
-        let mut vtable_base = 0;
-
-        move |segment| {
-            match segment {
-                VtblSegment::MetadataDSA => {
-                    vtable_base += TyCtxt::COMMON_VTABLE_ENTRIES.len();
-                }
-                VtblSegment::TraitOwnEntries { trait_ref, emit_vptr } => {
-                    if tcx.erase_regions(trait_ref) == trait_to_be_found_erased {
-                        return ControlFlow::Break(vtable_base);
-                    }
-                    vtable_base += util::count_own_vtable_entries(tcx, trait_ref);
-                    if emit_vptr {
-                        vtable_base += 1;
-                    }
-                }
-            }
-            ControlFlow::Continue(())
-        }
-    };
-
-    if let Some(vtable_base) =
-        prepare_vtable_segments(tcx, trait_owning_vtable, vtable_segment_callback)
-    {
-        vtable_base
-    } else {
-        bug!("Failed to find info for expected trait in vtable");
-    }
-}
-
-/// Find slot offset for trait vptr within vtable entries of another trait
-pub fn vtable_trait_upcasting_coercion_new_vptr_slot<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    key: (
-        Ty<'tcx>, // trait object type whose trait owning vtable
-        Ty<'tcx>, // trait object for supertrait
-    ),
-) -> Option<usize> {
-    let (source, target) = key;
-    assert!(matches!(&source.kind(), &ty::Dynamic(..)) && !source.needs_infer());
-    assert!(matches!(&target.kind(), &ty::Dynamic(..)) && !target.needs_infer());
-
-    // this has been typecked-before, so diagnostics is not really needed.
-    let unsize_trait_did = tcx.require_lang_item(LangItem::Unsize, None);
-
-    let trait_ref = tcx.mk_trait_ref(unsize_trait_did, [source, target]);
-
-    match tcx.codegen_select_candidate((ty::ParamEnv::reveal_all(), ty::Binder::dummy(trait_ref))) {
-        Ok(ImplSource::TraitUpcasting(implsrc_traitcasting)) => {
-            implsrc_traitcasting.vtable_vptr_slot
-        }
-        otherwise => bug!("expected TraitUpcasting candidate, got {otherwise:?}"),
-    }
-}
-
 pub fn provide(providers: &mut ty::query::Providers) {
     object_safety::provide(providers);
-    structural_match::provide(providers);
+    vtable::provide(providers);
     *providers = ty::query::Providers {
         specialization_graph_of: specialize::specialization_graph_provider,
         specializes: specialize::specializes,
-        codegen_select_candidate: codegen::codegen_select_candidate,
-        own_existential_vtable_entries,
-        vtable_entries,
-        vtable_trait_upcasting_coercion_new_vptr_slot,
         subst_and_check_impossible_predicates,
         is_impossible_method,
         ..*providers
index 113803cd1790ac362a3794731b2d6186ca108991..5789754e4fcefd6f19fa458f1f80cd5e4d7e5445 100644 (file)
 pub(super) struct InProgress;
 
 pub trait NormalizeExt<'tcx> {
+    /// Normalize a value using the `AssocTypeNormalizer`.
+    ///
+    /// This normalization should be used when the type contains inference variables or the
+    /// projection may be fallible.
     fn normalize<T: TypeFoldable<'tcx>>(&self, t: T) -> InferOk<'tcx, T>;
 }
 
@@ -57,7 +61,7 @@ impl<'tcx> NormalizeExt<'tcx> for At<'_, 'tcx> {
     fn normalize<T: TypeFoldable<'tcx>>(&self, value: T) -> InferOk<'tcx, T> {
         let mut selcx = SelectionContext::new(self.infcx);
         let Normalized { value, obligations } =
-            normalize(&mut selcx, self.param_env, self.cause.clone(), value);
+            normalize_with_depth(&mut selcx, self.param_env, self.cause.clone(), 0, value);
         InferOk { value, obligations }
     }
 }
@@ -303,37 +307,6 @@ fn project_and_unify_type<'cx, 'tcx>(
     }
 }
 
-/// Normalizes any associated type projections in `value`, replacing
-/// them with a fully resolved type where possible. The return value
-/// combines the normalized result and any additional obligations that
-/// were incurred as result.
-pub(crate) fn normalize<'a, 'b, 'tcx, T>(
-    selcx: &'a mut SelectionContext<'b, 'tcx>,
-    param_env: ty::ParamEnv<'tcx>,
-    cause: ObligationCause<'tcx>,
-    value: T,
-) -> Normalized<'tcx, T>
-where
-    T: TypeFoldable<'tcx>,
-{
-    let mut obligations = Vec::new();
-    let value = normalize_to(selcx, param_env, cause, value, &mut obligations);
-    Normalized { value, obligations }
-}
-
-pub(crate) fn normalize_to<'a, 'b, 'tcx, T>(
-    selcx: &'a mut SelectionContext<'b, 'tcx>,
-    param_env: ty::ParamEnv<'tcx>,
-    cause: ObligationCause<'tcx>,
-    value: T,
-    obligations: &mut Vec<PredicateObligation<'tcx>>,
-) -> T
-where
-    T: TypeFoldable<'tcx>,
-{
-    normalize_with_depth_to(selcx, param_env, cause, 0, value, obligations)
-}
-
 /// As `normalize`, but with a custom depth.
 pub(crate) fn normalize_with_depth<'a, 'b, 'tcx, T>(
     selcx: &'a mut SelectionContext<'b, 'tcx>,
@@ -531,14 +504,12 @@ fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
                     Reveal::All => {
                         let recursion_limit = self.tcx().recursion_limit();
                         if !recursion_limit.value_within_limit(self.depth) {
-                            let obligation = Obligation::with_depth(
-                                self.tcx(),
-                                self.cause.clone(),
-                                recursion_limit.0,
-                                self.param_env,
-                                ty,
+                            self.selcx.infcx.err_ctxt().report_overflow_error(
+                                &ty,
+                                self.cause.span,
+                                true,
+                                |_| {},
                             );
-                            self.selcx.infcx.err_ctxt().report_overflow_error(&obligation, true);
                         }
 
                         let substs = substs.fold_with(self);
@@ -2324,10 +2295,11 @@ fn confirm_impl_trait_in_trait_candidate<'tcx>(
         },
     ));
 
-    let ty = super::normalize_to(
+    let ty = normalize_with_depth_to(
         selcx,
         obligation.param_env,
         cause.clone(),
+        obligation.recursion_depth + 1,
         tcx.bound_trait_impl_trait_tys(impl_fn_def_id)
             .map_bound(|tys| {
                 tys.map_or_else(|_| tcx.ty_error(), |tys| tys[&obligation.predicate.item_def_id])
@@ -2347,11 +2319,10 @@ fn assoc_ty_own_obligations<'cx, 'tcx>(
     nested: &mut Vec<PredicateObligation<'tcx>>,
 ) {
     let tcx = selcx.tcx();
-    for predicate in tcx
+    let own = tcx
         .predicates_of(obligation.predicate.item_def_id)
-        .instantiate_own(tcx, obligation.predicate.substs)
-        .predicates
-    {
+        .instantiate_own(tcx, obligation.predicate.substs);
+    for (predicate, span) in std::iter::zip(own.predicates, own.spans) {
         let normalized = normalize_with_depth_to(
             selcx,
             obligation.param_env,
@@ -2360,9 +2331,30 @@ fn assoc_ty_own_obligations<'cx, 'tcx>(
             predicate,
             nested,
         );
+
+        let nested_cause = if matches!(
+            obligation.cause.code(),
+            super::CompareImplItemObligation { .. }
+                | super::CheckAssociatedTypeBounds { .. }
+                | super::AscribeUserTypeProvePredicate(..)
+        ) {
+            obligation.cause.clone()
+        } else if span.is_dummy() {
+            ObligationCause::new(
+                obligation.cause.span,
+                obligation.cause.body_id,
+                super::ItemObligation(obligation.predicate.item_def_id),
+            )
+        } else {
+            ObligationCause::new(
+                obligation.cause.span,
+                obligation.cause.body_id,
+                super::BindingObligation(obligation.predicate.item_def_id, span),
+            )
+        };
         nested.push(Obligation::with_depth(
             tcx,
-            obligation.cause.clone(),
+            nested_cause,
             obligation.recursion_depth + 1,
             obligation.param_env,
             normalized,
index 1aed66308709e33a8e43df92298e951c4d549b9d..7ad532d8a34645544996dd1930fbf45284d9d1b7 100644 (file)
@@ -7,7 +7,7 @@
 use crate::infer::{InferCtxt, InferOk};
 use crate::traits::error_reporting::TypeErrCtxtExt;
 use crate::traits::project::{needs_normalization, BoundVarReplacer, PlaceholderReplacer};
-use crate::traits::{Obligation, ObligationCause, PredicateObligation, Reveal};
+use crate::traits::{ObligationCause, PredicateObligation, Reveal};
 use rustc_data_structures::sso::SsoHashMap;
 use rustc_data_structures::stack::ensure_sufficient_stack;
 use rustc_infer::traits::Normalized;
 pub use rustc_middle::traits::query::NormalizationResult;
 
 pub trait QueryNormalizeExt<'tcx> {
+    /// Normalize a value using the `QueryNormalizer`.
+    ///
+    /// This normalization should *only* be used when the projection does not
+    /// have possible ambiguity or may not be well-formed.
+    ///
+    /// After codegen, when lifetimes do not matter, it is preferable to instead
+    /// use [`TyCtxt::normalize_erasing_regions`], which wraps this procedure.
     fn query_normalize<T>(&self, value: T) -> Result<Normalized<'tcx, T>, NoSolution>
     where
         T: TypeFoldable<'tcx>;
@@ -207,14 +214,12 @@ fn try_fold_ty(&mut self, ty: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
                         let substs = substs.try_fold_with(self)?;
                         let recursion_limit = self.tcx().recursion_limit();
                         if !recursion_limit.value_within_limit(self.anon_depth) {
-                            let obligation = Obligation::with_depth(
-                                self.tcx(),
-                                self.cause.clone(),
-                                recursion_limit.0,
-                                self.param_env,
-                                ty,
+                            self.infcx.err_ctxt().report_overflow_error(
+                                &ty,
+                                self.cause.span,
+                                true,
+                                |_| {},
                             );
-                            self.infcx.err_ctxt().report_overflow_error(&obligation, true);
                         }
 
                         let generic_ty = self.tcx().bound_type_of(def_id);
index fe5135661b5f8f3996649ee9519849d747ad08e3..e4b70f0d2ffa7afbfc54dbf7fdaa252400ef1226 100644 (file)
@@ -203,7 +203,9 @@ fn assemble_generator_candidates(
         // type/region parameters.
         let self_ty = obligation.self_ty().skip_binder();
         match self_ty.kind() {
-            ty::Generator(..) => {
+            // async constructs get lowered to a special kind of generator that
+            // should *not* `impl Generator`.
+            ty::Generator(did, ..) if !self.tcx().generator_is_async(*did) => {
                 debug!(?self_ty, ?obligation, "assemble_generator_candidates",);
 
                 candidates.vec.push(GeneratorCandidate);
@@ -223,6 +225,8 @@ fn assemble_future_candidates(
     ) {
         let self_ty = obligation.self_ty().skip_binder();
         if let ty::Generator(did, ..) = self_ty.kind() {
+            // async constructs get lowered to a special kind of generator that
+            // should directly `impl Future`.
             if self.tcx().generator_is_async(*did) {
                 debug!(?self_ty, ?obligation, "assemble_future_candidates",);
 
index 22cd700dcb5f4747705c2c31185cace511e59529..fda415155c469b556c3206ad8223431625388eaa 100644 (file)
 
 use crate::traits::project::{normalize_with_depth, normalize_with_depth_to};
 use crate::traits::util::{self, closure_trait_ref_and_return_type, predicate_for_trait_def};
+use crate::traits::vtable::{
+    count_own_vtable_entries, prepare_vtable_segments, vtable_trait_first_method_offset,
+    VtblSegment,
+};
 use crate::traits::{
     BuiltinDerivedObligation, ImplDerivedObligation, ImplDerivedObligationCause, ImplSource,
     ImplSourceAutoImplData, ImplSourceBuiltinData, ImplSourceClosureData,
@@ -26,7 +30,7 @@
     ImplSourceGeneratorData, ImplSourceObjectData, ImplSourceTraitAliasData,
     ImplSourceTraitUpcastingData, ImplSourceUserDefinedData, Normalized, ObjectCastObligation,
     Obligation, ObligationCause, OutputTypeParameterMismatch, PredicateObligation, Selection,
-    SelectionError, TraitNotObjectSafe, TraitObligation, Unimplemented, VtblSegment,
+    SelectionError, TraitNotObjectSafe, TraitObligation, Unimplemented,
 };
 
 use super::BuiltinImplConditions;
@@ -583,7 +587,7 @@ fn confirm_object_candidate(
 
         debug!(?nested, "object nested obligations");
 
-        let vtable_base = super::super::vtable_trait_first_method_offset(
+        let vtable_base = vtable_trait_first_method_offset(
             tcx,
             (unnormalized_upcast_trait_ref, ty::Binder::dummy(object_trait_ref)),
         );
@@ -904,7 +908,7 @@ fn confirm_trait_upcasting_unsize_candidate(
                         vptr_offset += TyCtxt::COMMON_VTABLE_ENTRIES.len();
                     }
                     VtblSegment::TraitOwnEntries { trait_ref, emit_vptr } => {
-                        vptr_offset += util::count_own_vtable_entries(tcx, trait_ref);
+                        vptr_offset += count_own_vtable_entries(tcx, trait_ref);
                         if trait_ref == upcast_trait_ref {
                             if emit_vptr {
                                 return ControlFlow::Break(Some(vptr_offset));
@@ -923,8 +927,7 @@ fn confirm_trait_upcasting_unsize_candidate(
         };
 
         let vtable_vptr_slot =
-            super::super::prepare_vtable_segments(tcx, source_trait_ref, vtable_segment_callback)
-                .unwrap();
+            prepare_vtable_segments(tcx, source_trait_ref, vtable_segment_callback).unwrap();
 
         Ok(ImplSourceTraitUpcastingData { upcast_trait_ref, vtable_vptr_slot, nested })
     }
index 515f3a34988869a77b50f5ccfa36619197032a47..035deb61639817c57d897a9ffdcb75db304aacaa 100644 (file)
@@ -43,7 +43,6 @@
 use rustc_middle::ty::abstract_const::NotConstEvaluatable;
 use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams};
 use rustc_middle::ty::fold::BottomUpFolder;
-use rustc_middle::ty::print::{FmtPrinter, Print};
 use rustc_middle::ty::relate::TypeRelation;
 use rustc_middle::ty::SubstsRef;
 use rustc_middle::ty::{self, EarlyBinder, PolyProjectionPredicate, ToPolyTraitRef, ToPredicate};
@@ -371,23 +370,28 @@ fn candidate_from_obligation_no_cache<'o>(
 
                     if !candidate_set.ambiguous && no_candidates_apply {
                         let trait_ref = stack.obligation.predicate.skip_binder().trait_ref;
-                        let self_ty = trait_ref.self_ty();
-                        let (trait_desc, self_desc) = with_no_trimmed_paths!({
-                            let trait_desc = trait_ref.print_only_trait_path().to_string();
-                            let self_desc = if self_ty.has_concrete_skeleton() {
-                                Some(self_ty.to_string())
+                        if !trait_ref.references_error() {
+                            let self_ty = trait_ref.self_ty();
+                            let (trait_desc, self_desc) = with_no_trimmed_paths!({
+                                let trait_desc = trait_ref.print_only_trait_path().to_string();
+                                let self_desc = if self_ty.has_concrete_skeleton() {
+                                    Some(self_ty.to_string())
+                                } else {
+                                    None
+                                };
+                                (trait_desc, self_desc)
+                            });
+                            let cause = if let Conflict::Upstream = conflict {
+                                IntercrateAmbiguityCause::UpstreamCrateUpdate {
+                                    trait_desc,
+                                    self_desc,
+                                }
                             } else {
-                                None
+                                IntercrateAmbiguityCause::DownstreamCrate { trait_desc, self_desc }
                             };
-                            (trait_desc, self_desc)
-                        });
-                        let cause = if let Conflict::Upstream = conflict {
-                            IntercrateAmbiguityCause::UpstreamCrateUpdate { trait_desc, self_desc }
-                        } else {
-                            IntercrateAmbiguityCause::DownstreamCrate { trait_desc, self_desc }
-                        };
-                        debug!(?cause, "evaluate_stack: pushing cause");
-                        self.intercrate_ambiguity_causes.as_mut().unwrap().insert(cause);
+                            debug!(?cause, "evaluate_stack: pushing cause");
+                            self.intercrate_ambiguity_causes.as_mut().unwrap().insert(cause);
+                        }
                     }
                 }
             }
@@ -1308,10 +1312,7 @@ fn check_recursion_depth<T>(
         error_obligation: &Obligation<'tcx, T>,
     ) -> Result<(), OverflowError>
     where
-        T: fmt::Display
-            + TypeFoldable<'tcx>
-            + Print<'tcx, FmtPrinter<'tcx, 'tcx>, Output = FmtPrinter<'tcx, 'tcx>>,
-        <T as Print<'tcx, FmtPrinter<'tcx, 'tcx>>>::Error: std::fmt::Debug,
+        T: ToPredicate<'tcx> + Clone,
     {
         if !self.infcx.tcx.recursion_limit().value_within_limit(depth) {
             match self.query_mode {
@@ -1319,7 +1320,7 @@ fn check_recursion_depth<T>(
                     if let Some(e) = self.infcx.tainted_by_errors() {
                         return Err(OverflowError::Error(e));
                     }
-                    self.infcx.err_ctxt().report_overflow_error(error_obligation, true);
+                    self.infcx.err_ctxt().report_overflow_obligation(error_obligation, true);
                 }
                 TraitQueryMode::Canonical => {
                     return Err(OverflowError::Canonical);
@@ -1340,10 +1341,7 @@ fn check_recursion_limit<T: Display + TypeFoldable<'tcx>, V>(
         error_obligation: &Obligation<'tcx, V>,
     ) -> Result<(), OverflowError>
     where
-        V: fmt::Display
-            + TypeFoldable<'tcx>
-            + Print<'tcx, FmtPrinter<'tcx, 'tcx>, Output = FmtPrinter<'tcx, 'tcx>>,
-        <V as Print<'tcx, FmtPrinter<'tcx, 'tcx>>>::Error: std::fmt::Debug,
+        V: ToPredicate<'tcx> + Clone,
     {
         self.check_recursion_depth(obligation.recursion_depth, error_obligation)
     }
index 40dbe0b3ff063d927dc78c3de0e2eefb1ab3b113..4dc08e0f9dab0da99be2c049b08e755c9f7c5b04 100644 (file)
@@ -1,10 +1,5 @@
-use crate::infer::{InferCtxt, TyCtxtInferExt};
-use crate::traits::{ObligationCause, ObligationCtxt};
-
 use rustc_data_structures::fx::FxHashSet;
 use rustc_hir as hir;
-use rustc_hir::lang_items::LangItem;
-use rustc_middle::ty::query::Providers;
 use rustc_middle::ty::{self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor};
 use rustc_span::Span;
 use std::ops::ControlFlow;
@@ -59,41 +54,6 @@ pub fn search_for_adt_const_param_violation<'tcx>(
         .break_value()
 }
 
-/// This method returns true if and only if `adt_ty` itself has been marked as
-/// eligible for structural-match: namely, if it implements both
-/// `StructuralPartialEq` and `StructuralEq` (which are respectively injected by
-/// `#[derive(PartialEq)]` and `#[derive(Eq)]`).
-///
-/// Note that this does *not* recursively check if the substructure of `adt_ty`
-/// implements the traits.
-fn type_marked_structural<'tcx>(
-    infcx: &InferCtxt<'tcx>,
-    adt_ty: Ty<'tcx>,
-    cause: ObligationCause<'tcx>,
-) -> bool {
-    let ocx = ObligationCtxt::new(infcx);
-    // require `#[derive(PartialEq)]`
-    let structural_peq_def_id =
-        infcx.tcx.require_lang_item(LangItem::StructuralPeq, Some(cause.span));
-    ocx.register_bound(cause.clone(), ty::ParamEnv::empty(), adt_ty, structural_peq_def_id);
-    // for now, require `#[derive(Eq)]`. (Doing so is a hack to work around
-    // the type `for<'a> fn(&'a ())` failing to implement `Eq` itself.)
-    let structural_teq_def_id =
-        infcx.tcx.require_lang_item(LangItem::StructuralTeq, Some(cause.span));
-    ocx.register_bound(cause, ty::ParamEnv::empty(), adt_ty, structural_teq_def_id);
-
-    // We deliberately skip *reporting* fulfillment errors (via
-    // `report_fulfillment_errors`), for two reasons:
-    //
-    // 1. The error messages would mention `std::marker::StructuralPartialEq`
-    //    (a trait which is solely meant as an implementation detail
-    //    for now), and
-    //
-    // 2. We are sometimes doing future-incompatibility lints for
-    //    now, so we do not want unconditional errors here.
-    ocx.select_all_or_error().is_empty()
-}
-
 /// This implements the traversal over the structure of a given type to try to
 /// find instances of ADTs (specifically structs or enums) that do not implement
 /// the structural-match traits (`StructuralPartialEq` and `StructuralEq`).
@@ -249,11 +209,3 @@ fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
         })
     }
 }
-
-pub fn provide(providers: &mut Providers) {
-    providers.has_structural_eq_impls = |tcx, ty| {
-        let infcx = tcx.infer_ctxt().build();
-        let cause = ObligationCause::dummy();
-        type_marked_structural(&infcx, ty, cause)
-    };
-}
index 51968c2d7a191fccc2bd21e17ff26b6a0ec343f1..f3ca6a6c779a06b9ca34b584dde18fe5775f0516 100644 (file)
@@ -261,16 +261,6 @@ pub fn upcast_choices<'tcx>(
     supertraits(tcx, source_trait_ref).filter(|r| r.def_id() == target_trait_def_id).collect()
 }
 
-/// Given a trait `trait_ref`, returns the number of vtable entries
-/// that come from `trait_ref`, excluding its supertraits. Used in
-/// computing the vtable base for an upcast trait of a trait object.
-pub fn count_own_vtable_entries<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    trait_ref: ty::PolyTraitRef<'tcx>,
-) -> usize {
-    tcx.own_existential_vtable_entries(trait_ref.def_id()).len()
-}
-
 /// Given an upcast trait object described by `object`, returns the
 /// index of the method `method_def_id` (which should be part of
 /// `object.upcast_trait_ref`) within the vtable for `object`.
diff --git a/compiler/rustc_trait_selection/src/traits/vtable.rs b/compiler/rustc_trait_selection/src/traits/vtable.rs
new file mode 100644 (file)
index 0000000..41ce6cd
--- /dev/null
@@ -0,0 +1,386 @@
+use crate::errors::DumpVTableEntries;
+use crate::traits::{impossible_predicates, is_vtable_safe_method};
+use rustc_hir::def_id::DefId;
+use rustc_hir::lang_items::LangItem;
+use rustc_infer::traits::util::PredicateSet;
+use rustc_infer::traits::ImplSource;
+use rustc_middle::ty::visit::TypeVisitable;
+use rustc_middle::ty::InternalSubsts;
+use rustc_middle::ty::{self, GenericParamDefKind, ToPredicate, Ty, TyCtxt, VtblEntry};
+use rustc_span::{sym, Span};
+use smallvec::SmallVec;
+
+use std::fmt::Debug;
+use std::ops::ControlFlow;
+
+#[derive(Clone, Debug)]
+pub(super) enum VtblSegment<'tcx> {
+    MetadataDSA,
+    TraitOwnEntries { trait_ref: ty::PolyTraitRef<'tcx>, emit_vptr: bool },
+}
+
+/// Prepare the segments for a vtable
+pub(super) fn prepare_vtable_segments<'tcx, T>(
+    tcx: TyCtxt<'tcx>,
+    trait_ref: ty::PolyTraitRef<'tcx>,
+    mut segment_visitor: impl FnMut(VtblSegment<'tcx>) -> ControlFlow<T>,
+) -> Option<T> {
+    // The following constraints holds for the final arrangement.
+    // 1. The whole virtual table of the first direct super trait is included as the
+    //    the prefix. If this trait doesn't have any super traits, then this step
+    //    consists of the dsa metadata.
+    // 2. Then comes the proper pointer metadata(vptr) and all own methods for all
+    //    other super traits except those already included as part of the first
+    //    direct super trait virtual table.
+    // 3. finally, the own methods of this trait.
+
+    // This has the advantage that trait upcasting to the first direct super trait on each level
+    // is zero cost, and to another trait includes only replacing the pointer with one level indirection,
+    // while not using too much extra memory.
+
+    // For a single inheritance relationship like this,
+    //   D --> C --> B --> A
+    // The resulting vtable will consists of these segments:
+    //  DSA, A, B, C, D
+
+    // For a multiple inheritance relationship like this,
+    //   D --> C --> A
+    //           \-> B
+    // The resulting vtable will consists of these segments:
+    //  DSA, A, B, B-vptr, C, D
+
+    // For a diamond inheritance relationship like this,
+    //   D --> B --> A
+    //     \-> C -/
+    // The resulting vtable will consists of these segments:
+    //  DSA, A, B, C, C-vptr, D
+
+    // For a more complex inheritance relationship like this:
+    //   O --> G --> C --> A
+    //     \     \     \-> B
+    //     |     |-> F --> D
+    //     |           \-> E
+    //     |-> N --> J --> H
+    //           \     \-> I
+    //           |-> M --> K
+    //                 \-> L
+    // The resulting vtable will consists of these segments:
+    //  DSA, A, B, B-vptr, C, D, D-vptr, E, E-vptr, F, F-vptr, G,
+    //  H, H-vptr, I, I-vptr, J, J-vptr, K, K-vptr, L, L-vptr, M, M-vptr,
+    //  N, N-vptr, O
+
+    // emit dsa segment first.
+    if let ControlFlow::Break(v) = (segment_visitor)(VtblSegment::MetadataDSA) {
+        return Some(v);
+    }
+
+    let mut emit_vptr_on_new_entry = false;
+    let mut visited = PredicateSet::new(tcx);
+    let predicate = trait_ref.without_const().to_predicate(tcx);
+    let mut stack: SmallVec<[(ty::PolyTraitRef<'tcx>, _, _); 5]> =
+        smallvec![(trait_ref, emit_vptr_on_new_entry, None)];
+    visited.insert(predicate);
+
+    // the main traversal loop:
+    // basically we want to cut the inheritance directed graph into a few non-overlapping slices of nodes
+    // that each node is emitted after all its descendents have been emitted.
+    // so we convert the directed graph into a tree by skipping all previously visited nodes using a visited set.
+    // this is done on the fly.
+    // Each loop run emits a slice - it starts by find a "childless" unvisited node, backtracking upwards, and it
+    // stops after it finds a node that has a next-sibling node.
+    // This next-sibling node will used as the starting point of next slice.
+
+    // Example:
+    // For a diamond inheritance relationship like this,
+    //   D#1 --> B#0 --> A#0
+    //     \-> C#1 -/
+
+    // Starting point 0 stack [D]
+    // Loop run #0: Stack after diving in is [D B A], A is "childless"
+    // after this point, all newly visited nodes won't have a vtable that equals to a prefix of this one.
+    // Loop run #0: Emitting the slice [B A] (in reverse order), B has a next-sibling node, so this slice stops here.
+    // Loop run #0: Stack after exiting out is [D C], C is the next starting point.
+    // Loop run #1: Stack after diving in is [D C], C is "childless", since its child A is skipped(already emitted).
+    // Loop run #1: Emitting the slice [D C] (in reverse order). No one has a next-sibling node.
+    // Loop run #1: Stack after exiting out is []. Now the function exits.
+
+    loop {
+        // dive deeper into the stack, recording the path
+        'diving_in: loop {
+            if let Some((inner_most_trait_ref, _, _)) = stack.last() {
+                let inner_most_trait_ref = *inner_most_trait_ref;
+                let mut direct_super_traits_iter = tcx
+                    .super_predicates_of(inner_most_trait_ref.def_id())
+                    .predicates
+                    .into_iter()
+                    .filter_map(move |(pred, _)| {
+                        pred.subst_supertrait(tcx, &inner_most_trait_ref).to_opt_poly_trait_pred()
+                    });
+
+                'diving_in_skip_visited_traits: loop {
+                    if let Some(next_super_trait) = direct_super_traits_iter.next() {
+                        if visited.insert(next_super_trait.to_predicate(tcx)) {
+                            // We're throwing away potential constness of super traits here.
+                            // FIXME: handle ~const super traits
+                            let next_super_trait = next_super_trait.map_bound(|t| t.trait_ref);
+                            stack.push((
+                                next_super_trait,
+                                emit_vptr_on_new_entry,
+                                Some(direct_super_traits_iter),
+                            ));
+                            break 'diving_in_skip_visited_traits;
+                        } else {
+                            continue 'diving_in_skip_visited_traits;
+                        }
+                    } else {
+                        break 'diving_in;
+                    }
+                }
+            }
+        }
+
+        // Other than the left-most path, vptr should be emitted for each trait.
+        emit_vptr_on_new_entry = true;
+
+        // emit innermost item, move to next sibling and stop there if possible, otherwise jump to outer level.
+        'exiting_out: loop {
+            if let Some((inner_most_trait_ref, emit_vptr, siblings_opt)) = stack.last_mut() {
+                if let ControlFlow::Break(v) = (segment_visitor)(VtblSegment::TraitOwnEntries {
+                    trait_ref: *inner_most_trait_ref,
+                    emit_vptr: *emit_vptr,
+                }) {
+                    return Some(v);
+                }
+
+                'exiting_out_skip_visited_traits: loop {
+                    if let Some(siblings) = siblings_opt {
+                        if let Some(next_inner_most_trait_ref) = siblings.next() {
+                            if visited.insert(next_inner_most_trait_ref.to_predicate(tcx)) {
+                                // We're throwing away potential constness of super traits here.
+                                // FIXME: handle ~const super traits
+                                let next_inner_most_trait_ref =
+                                    next_inner_most_trait_ref.map_bound(|t| t.trait_ref);
+                                *inner_most_trait_ref = next_inner_most_trait_ref;
+                                *emit_vptr = emit_vptr_on_new_entry;
+                                break 'exiting_out;
+                            } else {
+                                continue 'exiting_out_skip_visited_traits;
+                            }
+                        }
+                    }
+                    stack.pop();
+                    continue 'exiting_out;
+                }
+            }
+            // all done
+            return None;
+        }
+    }
+}
+
+fn dump_vtable_entries<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    sp: Span,
+    trait_ref: ty::PolyTraitRef<'tcx>,
+    entries: &[VtblEntry<'tcx>],
+) {
+    tcx.sess.emit_err(DumpVTableEntries {
+        span: sp,
+        trait_ref,
+        entries: format!("{:#?}", entries),
+    });
+}
+
+fn own_existential_vtable_entries<'tcx>(tcx: TyCtxt<'tcx>, trait_def_id: DefId) -> &'tcx [DefId] {
+    let trait_methods = tcx
+        .associated_items(trait_def_id)
+        .in_definition_order()
+        .filter(|item| item.kind == ty::AssocKind::Fn);
+    // Now list each method's DefId (for within its trait).
+    let own_entries = trait_methods.filter_map(move |trait_method| {
+        debug!("own_existential_vtable_entry: trait_method={:?}", trait_method);
+        let def_id = trait_method.def_id;
+
+        // Some methods cannot be called on an object; skip those.
+        if !is_vtable_safe_method(tcx, trait_def_id, &trait_method) {
+            debug!("own_existential_vtable_entry: not vtable safe");
+            return None;
+        }
+
+        Some(def_id)
+    });
+
+    tcx.arena.alloc_from_iter(own_entries.into_iter())
+}
+
+/// Given a trait `trait_ref`, iterates the vtable entries
+/// that come from `trait_ref`, including its supertraits.
+fn vtable_entries<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    trait_ref: ty::PolyTraitRef<'tcx>,
+) -> &'tcx [VtblEntry<'tcx>] {
+    debug!("vtable_entries({:?})", trait_ref);
+
+    let mut entries = vec![];
+
+    let vtable_segment_callback = |segment| -> ControlFlow<()> {
+        match segment {
+            VtblSegment::MetadataDSA => {
+                entries.extend(TyCtxt::COMMON_VTABLE_ENTRIES);
+            }
+            VtblSegment::TraitOwnEntries { trait_ref, emit_vptr } => {
+                let existential_trait_ref = trait_ref
+                    .map_bound(|trait_ref| ty::ExistentialTraitRef::erase_self_ty(tcx, trait_ref));
+
+                // Lookup the shape of vtable for the trait.
+                let own_existential_entries =
+                    tcx.own_existential_vtable_entries(existential_trait_ref.def_id());
+
+                let own_entries = own_existential_entries.iter().copied().map(|def_id| {
+                    debug!("vtable_entries: trait_method={:?}", def_id);
+
+                    // The method may have some early-bound lifetimes; add regions for those.
+                    let substs = trait_ref.map_bound(|trait_ref| {
+                        InternalSubsts::for_item(tcx, def_id, |param, _| match param.kind {
+                            GenericParamDefKind::Lifetime => tcx.lifetimes.re_erased.into(),
+                            GenericParamDefKind::Type { .. }
+                            | GenericParamDefKind::Const { .. } => {
+                                trait_ref.substs[param.index as usize]
+                            }
+                        })
+                    });
+
+                    // The trait type may have higher-ranked lifetimes in it;
+                    // erase them if they appear, so that we get the type
+                    // at some particular call site.
+                    let substs = tcx
+                        .normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), substs);
+
+                    // It's possible that the method relies on where-clauses that
+                    // do not hold for this particular set of type parameters.
+                    // Note that this method could then never be called, so we
+                    // do not want to try and codegen it, in that case (see #23435).
+                    let predicates = tcx.predicates_of(def_id).instantiate_own(tcx, substs);
+                    if impossible_predicates(tcx, predicates.predicates) {
+                        debug!("vtable_entries: predicates do not hold");
+                        return VtblEntry::Vacant;
+                    }
+
+                    let instance = ty::Instance::resolve_for_vtable(
+                        tcx,
+                        ty::ParamEnv::reveal_all(),
+                        def_id,
+                        substs,
+                    )
+                    .expect("resolution failed during building vtable representation");
+                    VtblEntry::Method(instance)
+                });
+
+                entries.extend(own_entries);
+
+                if emit_vptr {
+                    entries.push(VtblEntry::TraitVPtr(trait_ref));
+                }
+            }
+        }
+
+        ControlFlow::Continue(())
+    };
+
+    let _ = prepare_vtable_segments(tcx, trait_ref, vtable_segment_callback);
+
+    if tcx.has_attr(trait_ref.def_id(), sym::rustc_dump_vtable) {
+        let sp = tcx.def_span(trait_ref.def_id());
+        dump_vtable_entries(tcx, sp, trait_ref, &entries);
+    }
+
+    tcx.arena.alloc_from_iter(entries.into_iter())
+}
+
+/// Find slot base for trait methods within vtable entries of another trait
+pub(super) fn vtable_trait_first_method_offset<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    key: (
+        ty::PolyTraitRef<'tcx>, // trait_to_be_found
+        ty::PolyTraitRef<'tcx>, // trait_owning_vtable
+    ),
+) -> usize {
+    let (trait_to_be_found, trait_owning_vtable) = key;
+
+    // #90177
+    let trait_to_be_found_erased = tcx.erase_regions(trait_to_be_found);
+
+    let vtable_segment_callback = {
+        let mut vtable_base = 0;
+
+        move |segment| {
+            match segment {
+                VtblSegment::MetadataDSA => {
+                    vtable_base += TyCtxt::COMMON_VTABLE_ENTRIES.len();
+                }
+                VtblSegment::TraitOwnEntries { trait_ref, emit_vptr } => {
+                    if tcx.erase_regions(trait_ref) == trait_to_be_found_erased {
+                        return ControlFlow::Break(vtable_base);
+                    }
+                    vtable_base += count_own_vtable_entries(tcx, trait_ref);
+                    if emit_vptr {
+                        vtable_base += 1;
+                    }
+                }
+            }
+            ControlFlow::Continue(())
+        }
+    };
+
+    if let Some(vtable_base) =
+        prepare_vtable_segments(tcx, trait_owning_vtable, vtable_segment_callback)
+    {
+        vtable_base
+    } else {
+        bug!("Failed to find info for expected trait in vtable");
+    }
+}
+
+/// Find slot offset for trait vptr within vtable entries of another trait
+pub(crate) fn vtable_trait_upcasting_coercion_new_vptr_slot<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    key: (
+        Ty<'tcx>, // trait object type whose trait owning vtable
+        Ty<'tcx>, // trait object for supertrait
+    ),
+) -> Option<usize> {
+    let (source, target) = key;
+    assert!(matches!(&source.kind(), &ty::Dynamic(..)) && !source.needs_infer());
+    assert!(matches!(&target.kind(), &ty::Dynamic(..)) && !target.needs_infer());
+
+    // this has been typecked-before, so diagnostics is not really needed.
+    let unsize_trait_did = tcx.require_lang_item(LangItem::Unsize, None);
+
+    let trait_ref = tcx.mk_trait_ref(unsize_trait_did, [source, target]);
+
+    match tcx.codegen_select_candidate((ty::ParamEnv::reveal_all(), ty::Binder::dummy(trait_ref))) {
+        Ok(ImplSource::TraitUpcasting(implsrc_traitcasting)) => {
+            implsrc_traitcasting.vtable_vptr_slot
+        }
+        otherwise => bug!("expected TraitUpcasting candidate, got {otherwise:?}"),
+    }
+}
+
+/// Given a trait `trait_ref`, returns the number of vtable entries
+/// that come from `trait_ref`, excluding its supertraits. Used in
+/// computing the vtable base for an upcast trait of a trait object.
+pub(crate) fn count_own_vtable_entries<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    trait_ref: ty::PolyTraitRef<'tcx>,
+) -> usize {
+    tcx.own_existential_vtable_entries(trait_ref.def_id()).len()
+}
+
+pub(super) fn provide(providers: &mut ty::query::Providers) {
+    *providers = ty::query::Providers {
+        own_existential_vtable_entries,
+        vtable_entries,
+        vtable_trait_upcasting_coercion_new_vptr_slot,
+        ..*providers
+    };
+}
index 0855d6d19736f15d91a39eb63d2bd17724005916..e47ba64245f50732f0b95a7eddf143b5341bc555 100644 (file)
@@ -476,9 +476,24 @@ fn compute(&mut self, arg: GenericArg<'tcx>) {
                                 ty::Binder::dummy(ty::PredicateKind::WellFormed(ct.into())),
                             ));
                         }
-                        // FIXME(generic_const_exprs): This seems wrong but I could not find a way to get this to trigger
                         ty::ConstKind::Expr(_) => {
-                            bug!("checking wfness of `ConstKind::Expr` is unsupported")
+                            // FIXME(generic_const_exprs): this doesnt verify that given `Expr(N + 1)` the
+                            // trait bound `typeof(N): Add<typeof(1)>` holds. This is currently unnecessary
+                            // as `ConstKind::Expr` is only produced via normalization of `ConstKind::Unevaluated`
+                            // which means that the `DefId` would have been typeck'd elsewhere. However in
+                            // the future we may allow directly lowering to `ConstKind::Expr` in which case
+                            // we would not be proving bounds we should.
+
+                            let predicate =
+                                ty::Binder::dummy(ty::PredicateKind::ConstEvaluatable(ct));
+                            let cause = self.cause(traits::WellFormed(None));
+                            self.out.push(traits::Obligation::with_depth(
+                                self.tcx(),
+                                cause,
+                                self.recursion_depth,
+                                self.param_env,
+                                predicate,
+                            ));
                         }
 
                         ty::ConstKind::Error(_)
diff --git a/compiler/rustc_traits/src/codegen.rs b/compiler/rustc_traits/src/codegen.rs
new file mode 100644 (file)
index 0000000..f8f74b7
--- /dev/null
@@ -0,0 +1,88 @@
+// This file contains various trait resolution methods used by codegen.
+// They all assume regions can be erased and monomorphic types.  It
+// seems likely that they should eventually be merged into more
+// general routines.
+
+use rustc_infer::infer::{DefiningAnchor, TyCtxtInferExt};
+use rustc_infer::traits::FulfillmentErrorCode;
+use rustc_middle::traits::CodegenObligationError;
+use rustc_middle::ty::{self, TyCtxt};
+use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt;
+use rustc_trait_selection::traits::{
+    ImplSource, Obligation, ObligationCause, SelectionContext, TraitEngine, TraitEngineExt,
+    Unimplemented,
+};
+
+/// Attempts to resolve an obligation to an `ImplSource`. The result is
+/// a shallow `ImplSource` resolution, meaning that we do not
+/// (necessarily) resolve all nested obligations on the impl. Note
+/// that type check should guarantee to us that all nested
+/// obligations *could be* resolved if we wanted to.
+///
+/// This also expects that `trait_ref` is fully normalized.
+pub fn codegen_select_candidate<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    (param_env, trait_ref): (ty::ParamEnv<'tcx>, ty::PolyTraitRef<'tcx>),
+) -> Result<&'tcx ImplSource<'tcx, ()>, CodegenObligationError> {
+    // We expect the input to be fully normalized.
+    debug_assert_eq!(trait_ref, tcx.normalize_erasing_regions(param_env, trait_ref));
+
+    // Do the initial selection for the obligation. This yields the
+    // shallow result we are looking for -- that is, what specific impl.
+    let infcx = tcx
+        .infer_ctxt()
+        .ignoring_regions()
+        .with_opaque_type_inference(DefiningAnchor::Bubble)
+        .build();
+    //~^ HACK `Bubble` is required for
+    // this test to pass: type-alias-impl-trait/assoc-projection-ice.rs
+    let mut selcx = SelectionContext::new(&infcx);
+
+    let obligation_cause = ObligationCause::dummy();
+    let obligation = Obligation::new(tcx, obligation_cause, param_env, trait_ref);
+
+    let selection = match selcx.select(&obligation) {
+        Ok(Some(selection)) => selection,
+        Ok(None) => return Err(CodegenObligationError::Ambiguity),
+        Err(Unimplemented) => return Err(CodegenObligationError::Unimplemented),
+        Err(e) => {
+            bug!("Encountered error `{:?}` selecting `{:?}` during codegen", e, trait_ref)
+        }
+    };
+
+    debug!(?selection);
+
+    // Currently, we use a fulfillment context to completely resolve
+    // all nested obligations. This is because they can inform the
+    // inference of the impl's type parameters.
+    let mut fulfill_cx = <dyn TraitEngine<'tcx>>::new(tcx);
+    let impl_source = selection.map(|predicate| {
+        fulfill_cx.register_predicate_obligation(&infcx, predicate);
+    });
+
+    // In principle, we only need to do this so long as `impl_source`
+    // contains unbound type parameters. It could be a slight
+    // optimization to stop iterating early.
+    let errors = fulfill_cx.select_all_or_error(&infcx);
+    if !errors.is_empty() {
+        // `rustc_monomorphize::collector` assumes there are no type errors.
+        // Cycle errors are the only post-monomorphization errors possible; emit them now so
+        // `rustc_ty_utils::resolve_associated_item` doesn't return `None` post-monomorphization.
+        for err in errors {
+            if let FulfillmentErrorCode::CodeCycle(cycle) = err.code {
+                infcx.err_ctxt().report_overflow_obligation_cycle(&cycle);
+            }
+        }
+        return Err(CodegenObligationError::FulfillmentError);
+    }
+
+    let impl_source = infcx.resolve_vars_if_possible(impl_source);
+    let impl_source = infcx.tcx.erase_regions(impl_source);
+
+    // Opaque types may have gotten their hidden types constrained, but we can ignore them safely
+    // as they will get constrained elsewhere, too.
+    // (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();
+
+    Ok(&*tcx.arena.alloc(impl_source))
+}
index 0ffa92f1ad55d960310e1625e13f53c362ea0e09..9aa26667e7bf461ef3059ade70551ccff81ee75e 100644 (file)
@@ -12,6 +12,7 @@
 extern crate rustc_middle;
 
 mod chalk;
+mod codegen;
 mod dropck_outlives;
 mod evaluate_obligation;
 mod implied_outlives_bounds;
@@ -31,4 +32,5 @@ pub fn provide(p: &mut Providers) {
     normalize_projection_ty::provide(p);
     normalize_erasing_regions::provide(p);
     type_op::provide(p);
+    p.codegen_select_candidate = codegen::codegen_select_candidate;
 }
index 73c7eb6992f075610dd2cac96d23c64c564a1e7a..d644cbccea11b2df6c5080a2191ad3c1c8b8f4f1 100644 (file)
@@ -85,7 +85,7 @@ fn fn_sig_for_fn_abi<'tcx>(
                 bound_vars,
             )
         }
-        ty::Generator(_, substs, _) => {
+        ty::Generator(did, substs, _) => {
             let sig = substs.as_generator().poly_sig();
 
             let bound_vars = tcx.mk_bound_variable_kinds(
@@ -104,10 +104,22 @@ fn fn_sig_for_fn_abi<'tcx>(
             let env_ty = tcx.mk_adt(pin_adt_ref, pin_substs);
 
             let sig = sig.skip_binder();
-            let state_did = tcx.require_lang_item(LangItem::GeneratorState, None);
-            let state_adt_ref = tcx.adt_def(state_did);
-            let state_substs = tcx.intern_substs(&[sig.yield_ty.into(), sig.return_ty.into()]);
-            let ret_ty = tcx.mk_adt(state_adt_ref, state_substs);
+            // The `FnSig` and the `ret_ty` here is for a generators main
+            // `Generator::resume(...) -> GeneratorState` function in case we
+            // have an ordinary generator, or the `Future::poll(...) -> Poll`
+            // function in case this is a special generator backing an async construct.
+            let ret_ty = if tcx.generator_is_async(did) {
+                let state_did = tcx.require_lang_item(LangItem::Poll, None);
+                let state_adt_ref = tcx.adt_def(state_did);
+                let state_substs = tcx.intern_substs(&[sig.return_ty.into()]);
+                tcx.mk_adt(state_adt_ref, state_substs)
+            } else {
+                let state_did = tcx.require_lang_item(LangItem::GeneratorState, None);
+                let state_adt_ref = tcx.adt_def(state_did);
+                let state_substs = tcx.intern_substs(&[sig.yield_ty.into(), sig.return_ty.into()]);
+                tcx.mk_adt(state_adt_ref, state_substs)
+            };
+
             ty::Binder::bind_with_vars(
                 tcx.mk_fn_sig(
                     [env_ty, sig.resume_ty].iter(),
index fbc055b5d238f8690555df090b99c3e267f4b126..f4672a70072b2b30ce8435d350d898bfa2e8c4c3 100644 (file)
@@ -1,3 +1,4 @@
+use hir::def_id::DefId;
 use rustc_hir as hir;
 use rustc_index::bit_set::BitSet;
 use rustc_index::vec::{Idx, IndexVec};
@@ -6,7 +7,7 @@
     IntegerExt, LayoutCx, LayoutError, LayoutOf, TyAndLayout, MAX_SIMD_LANES,
 };
 use rustc_middle::ty::{
-    self, subst::SubstsRef, EarlyBinder, ReprOptions, Ty, TyCtxt, TypeVisitable,
+    self, subst::SubstsRef, AdtDef, EarlyBinder, ReprOptions, Ty, TyCtxt, TypeVisitable,
 };
 use rustc_session::{DataTypeKind, FieldInfo, SizeKind, VariantInfo};
 use rustc_span::symbol::Symbol;
@@ -814,27 +815,39 @@ fn record_layout_for_printing_outlined<'tcx>(
         );
     };
 
-    let adt_def = match *layout.ty.kind() {
-        ty::Adt(ref adt_def, _) => {
+    match *layout.ty.kind() {
+        ty::Adt(adt_def, _) => {
             debug!("print-type-size t: `{:?}` process adt", layout.ty);
-            adt_def
+            let adt_kind = adt_def.adt_kind();
+            let adt_packed = adt_def.repr().pack.is_some();
+            let (variant_infos, opt_discr_size) = variant_info_for_adt(cx, layout, adt_def);
+            record(adt_kind.into(), adt_packed, opt_discr_size, variant_infos);
+        }
+
+        ty::Generator(def_id, substs, _) => {
+            debug!("print-type-size t: `{:?}` record generator", layout.ty);
+            // Generators always have a begin/poisoned/end state with additional suspend points
+            let (variant_infos, opt_discr_size) =
+                variant_info_for_generator(cx, layout, def_id, substs);
+            record(DataTypeKind::Generator, false, opt_discr_size, variant_infos);
         }
 
         ty::Closure(..) => {
             debug!("print-type-size t: `{:?}` record closure", layout.ty);
             record(DataTypeKind::Closure, false, None, vec![]);
-            return;
         }
 
         _ => {
             debug!("print-type-size t: `{:?}` skip non-nominal", layout.ty);
-            return;
         }
     };
+}
 
-    let adt_kind = adt_def.adt_kind();
-    let adt_packed = adt_def.repr().pack.is_some();
-
+fn variant_info_for_adt<'tcx>(
+    cx: &LayoutCx<'tcx, TyCtxt<'tcx>>,
+    layout: TyAndLayout<'tcx>,
+    adt_def: AdtDef<'tcx>,
+) -> (Vec<VariantInfo>, Option<Size>) {
     let build_variant_info = |n: Option<Symbol>, flds: &[Symbol], layout: TyAndLayout<'tcx>| {
         let mut min_size = Size::ZERO;
         let field_info: Vec<_> = flds
@@ -843,10 +856,7 @@ fn record_layout_for_printing_outlined<'tcx>(
             .map(|(i, &name)| {
                 let field_layout = layout.field(cx, i);
                 let offset = layout.fields.offset(i);
-                let field_end = offset + field_layout.size;
-                if min_size < field_end {
-                    min_size = field_end;
-                }
+                min_size = min_size.max(offset + field_layout.size);
                 FieldInfo {
                     name,
                     offset: offset.bytes(),
@@ -871,16 +881,9 @@ fn record_layout_for_printing_outlined<'tcx>(
                 debug!("print-type-size `{:#?}` variant {}", layout, adt_def.variant(index).name);
                 let variant_def = &adt_def.variant(index);
                 let fields: Vec<_> = variant_def.fields.iter().map(|f| f.name).collect();
-                record(
-                    adt_kind.into(),
-                    adt_packed,
-                    None,
-                    vec![build_variant_info(Some(variant_def.name), &fields, layout)],
-                );
+                (vec![build_variant_info(Some(variant_def.name), &fields, layout)], None)
             } else {
-                // (This case arises for *empty* enums; so give it
-                // zero variants.)
-                record(adt_kind.into(), adt_packed, None, vec![]);
+                (vec![], None)
             }
         }
 
@@ -898,15 +901,101 @@ fn record_layout_for_printing_outlined<'tcx>(
                     build_variant_info(Some(variant_def.name), &fields, layout.for_variant(cx, i))
                 })
                 .collect();
-            record(
-                adt_kind.into(),
-                adt_packed,
+
+            (
+                variant_infos,
                 match tag_encoding {
                     TagEncoding::Direct => Some(tag.size(cx)),
                     _ => None,
                 },
-                variant_infos,
-            );
+            )
         }
     }
 }
+
+fn variant_info_for_generator<'tcx>(
+    cx: &LayoutCx<'tcx, TyCtxt<'tcx>>,
+    layout: TyAndLayout<'tcx>,
+    def_id: DefId,
+    substs: ty::SubstsRef<'tcx>,
+) -> (Vec<VariantInfo>, Option<Size>) {
+    let Variants::Multiple { tag, ref tag_encoding, .. } = layout.variants else {
+        return (vec![], None);
+    };
+
+    let (generator, state_specific_names) = cx.tcx.generator_layout_and_saved_local_names(def_id);
+    let upvar_names = cx.tcx.closure_saved_names_of_captured_variables(def_id);
+
+    let mut upvars_size = Size::ZERO;
+    let upvar_fields: Vec<_> = substs
+        .as_generator()
+        .upvar_tys()
+        .zip(upvar_names)
+        .enumerate()
+        .map(|(field_idx, (_, name))| {
+            let field_layout = layout.field(cx, field_idx);
+            let offset = layout.fields.offset(field_idx);
+            upvars_size = upvars_size.max(offset + field_layout.size);
+            FieldInfo {
+                name: Symbol::intern(&name),
+                offset: offset.bytes(),
+                size: field_layout.size.bytes(),
+                align: field_layout.align.abi.bytes(),
+            }
+        })
+        .collect();
+
+    let variant_infos: Vec<_> = generator
+        .variant_fields
+        .iter_enumerated()
+        .map(|(variant_idx, variant_def)| {
+            let variant_layout = layout.for_variant(cx, variant_idx);
+            let mut variant_size = Size::ZERO;
+            let fields = variant_def
+                .iter()
+                .enumerate()
+                .map(|(field_idx, local)| {
+                    let field_layout = variant_layout.field(cx, field_idx);
+                    let offset = variant_layout.fields.offset(field_idx);
+                    // The struct is as large as the last field's end
+                    variant_size = variant_size.max(offset + field_layout.size);
+                    FieldInfo {
+                        name: state_specific_names.get(*local).copied().flatten().unwrap_or(
+                            Symbol::intern(&format!(".generator_field{}", local.as_usize())),
+                        ),
+                        offset: offset.bytes(),
+                        size: field_layout.size.bytes(),
+                        align: field_layout.align.abi.bytes(),
+                    }
+                })
+                .chain(upvar_fields.iter().copied())
+                .collect();
+
+            // If the variant has no state-specific fields, then it's the size of the upvars.
+            if variant_size == Size::ZERO {
+                variant_size = upvars_size;
+            }
+            // We need to add the discriminant size back into min_size, since it is subtracted
+            // later during printing.
+            variant_size += match tag_encoding {
+                TagEncoding::Direct => tag.size(cx),
+                _ => Size::ZERO,
+            };
+
+            VariantInfo {
+                name: Some(Symbol::intern(&ty::GeneratorSubsts::variant_name(variant_idx))),
+                kind: SizeKind::Exact,
+                size: variant_size.bytes(),
+                align: variant_layout.align.abi.bytes(),
+                fields,
+            }
+        })
+        .collect();
+    (
+        variant_infos,
+        match tag_encoding {
+            TagEncoding::Direct => Some(tag.size(cx)),
+            _ => None,
+        },
+    )
+}
index cce5a79ddc855cbcc5970c55855cb94edafb0fdb..7ad5cbc01ccf25293c116f05025bca179b33d0e3 100644 (file)
@@ -29,6 +29,7 @@
 mod layout_sanity_check;
 mod needs_drop;
 pub mod representability;
+mod structural_match;
 mod ty;
 
 pub fn provide(providers: &mut Providers) {
@@ -42,4 +43,5 @@ pub fn provide(providers: &mut Providers) {
     representability::provide(providers);
     ty::provide(providers);
     instance::provide(providers);
+    structural_match::provide(providers);
 }
diff --git a/compiler/rustc_ty_utils/src/structural_match.rs b/compiler/rustc_ty_utils/src/structural_match.rs
new file mode 100644 (file)
index 0000000..a55bb7e
--- /dev/null
@@ -0,0 +1,44 @@
+use rustc_hir::lang_items::LangItem;
+use rustc_middle::ty::query::Providers;
+use rustc_middle::ty::{self, Ty, TyCtxt};
+
+use rustc_infer::infer::TyCtxtInferExt;
+use rustc_trait_selection::traits::{ObligationCause, ObligationCtxt};
+
+/// This method returns true if and only if `adt_ty` itself has been marked as
+/// eligible for structural-match: namely, if it implements both
+/// `StructuralPartialEq` and `StructuralEq` (which are respectively injected by
+/// `#[derive(PartialEq)]` and `#[derive(Eq)]`).
+///
+/// Note that this does *not* recursively check if the substructure of `adt_ty`
+/// implements the traits.
+fn has_structural_eq_impls<'tcx>(tcx: TyCtxt<'tcx>, adt_ty: Ty<'tcx>) -> bool {
+    let ref infcx = tcx.infer_ctxt().build();
+    let cause = ObligationCause::dummy();
+
+    let ocx = ObligationCtxt::new(infcx);
+    // require `#[derive(PartialEq)]`
+    let structural_peq_def_id =
+        infcx.tcx.require_lang_item(LangItem::StructuralPeq, Some(cause.span));
+    ocx.register_bound(cause.clone(), ty::ParamEnv::empty(), adt_ty, structural_peq_def_id);
+    // for now, require `#[derive(Eq)]`. (Doing so is a hack to work around
+    // the type `for<'a> fn(&'a ())` failing to implement `Eq` itself.)
+    let structural_teq_def_id =
+        infcx.tcx.require_lang_item(LangItem::StructuralTeq, Some(cause.span));
+    ocx.register_bound(cause, ty::ParamEnv::empty(), adt_ty, structural_teq_def_id);
+
+    // We deliberately skip *reporting* fulfillment errors (via
+    // `report_fulfillment_errors`), for two reasons:
+    //
+    // 1. The error messages would mention `std::marker::StructuralPartialEq`
+    //    (a trait which is solely meant as an implementation detail
+    //    for now), and
+    //
+    // 2. We are sometimes doing future-incompatibility lints for
+    //    now, so we do not want unconditional errors here.
+    ocx.select_all_or_error().is_empty()
+}
+
+pub fn provide(providers: &mut Providers) {
+    providers.has_structural_eq_impls = has_structural_eq_impls;
+}
index 581993ba7d863eb2f22166a042764fae43e7d360..e3f7a1bd033cea39b7ed706a45ed49ce7e8474e6 100644 (file)
 
 pub mod codec;
 pub mod sty;
+pub mod ty_info;
 
 pub use codec::*;
 pub use sty::*;
+pub use ty_info::*;
 
 /// Needed so we can use #[derive(HashStable_Generic)]
 pub trait HashStableContext {}
index 02cbb2e858f80ac0943792604990d8e8c15727d9..9aa2be124e294871f24d11a82d2d168755d5fc00 100644 (file)
@@ -1,6 +1,6 @@
 #![allow(rustc::usage_of_ty_tykind)]
 
-use std::cmp::{Eq, Ord, Ordering, PartialEq, PartialOrd};
+use std::cmp::Ordering;
 use std::{fmt, hash};
 
 use crate::DebruijnIndex;
@@ -301,61 +301,44 @@ fn clone(&self) -> Self {
 impl<I: Interner> PartialEq for TyKind<I> {
     #[inline]
     fn eq(&self, other: &TyKind<I>) -> bool {
-        let __self_vi = tykind_discriminant(self);
-        let __arg_1_vi = tykind_discriminant(other);
-        if __self_vi == __arg_1_vi {
-            match (&*self, &*other) {
-                (&Int(ref __self_0), &Int(ref __arg_1_0)) => __self_0 == __arg_1_0,
-                (&Uint(ref __self_0), &Uint(ref __arg_1_0)) => __self_0 == __arg_1_0,
-                (&Float(ref __self_0), &Float(ref __arg_1_0)) => __self_0 == __arg_1_0,
-                (&Adt(ref __self_0, ref __self_1), &Adt(ref __arg_1_0, ref __arg_1_1)) => {
-                    __self_0 == __arg_1_0 && __self_1 == __arg_1_1
+        tykind_discriminant(self) == tykind_discriminant(other)
+            && match (self, other) {
+                (Int(a_i), Int(b_i)) => a_i == b_i,
+                (Uint(a_u), Uint(b_u)) => a_u == b_u,
+                (Float(a_f), Float(b_f)) => a_f == b_f,
+                (Adt(a_d, a_s), Adt(b_d, b_s)) => a_d == b_d && a_s == b_s,
+                (Foreign(a_d), Foreign(b_d)) => a_d == b_d,
+                (Array(a_t, a_c), Array(b_t, b_c)) => a_t == b_t && a_c == b_c,
+                (Slice(a_t), Slice(b_t)) => a_t == b_t,
+                (RawPtr(a_t), RawPtr(b_t)) => a_t == b_t,
+                (Ref(a_r, a_t, a_m), Ref(b_r, b_t, b_m)) => a_r == b_r && a_t == b_t && a_m == b_m,
+                (FnDef(a_d, a_s), FnDef(b_d, b_s)) => a_d == b_d && a_s == b_s,
+                (FnPtr(a_s), FnPtr(b_s)) => a_s == b_s,
+                (Dynamic(a_p, a_r, a_repr), Dynamic(b_p, b_r, b_repr)) => {
+                    a_p == b_p && a_r == b_r && a_repr == b_repr
                 }
-                (&Foreign(ref __self_0), &Foreign(ref __arg_1_0)) => __self_0 == __arg_1_0,
-                (&Array(ref __self_0, ref __self_1), &Array(ref __arg_1_0, ref __arg_1_1)) => {
-                    __self_0 == __arg_1_0 && __self_1 == __arg_1_1
+                (Closure(a_d, a_s), Closure(b_d, b_s)) => a_d == b_d && a_s == b_s,
+                (Generator(a_d, a_s, a_m), Generator(b_d, b_s, b_m)) => {
+                    a_d == b_d && a_s == b_s && a_m == b_m
                 }
-                (&Slice(ref __self_0), &Slice(ref __arg_1_0)) => __self_0 == __arg_1_0,
-                (&RawPtr(ref __self_0), &RawPtr(ref __arg_1_0)) => __self_0 == __arg_1_0,
-                (
-                    &Ref(ref __self_0, ref __self_1, ref __self_2),
-                    &Ref(ref __arg_1_0, ref __arg_1_1, ref __arg_1_2),
-                ) => __self_0 == __arg_1_0 && __self_1 == __arg_1_1 && __self_2 == __arg_1_2,
-                (&FnDef(ref __self_0, ref __self_1), &FnDef(ref __arg_1_0, ref __arg_1_1)) => {
-                    __self_0 == __arg_1_0 && __self_1 == __arg_1_1
+                (GeneratorWitness(a_g), GeneratorWitness(b_g)) => a_g == b_g,
+                (Tuple(a_t), Tuple(b_t)) => a_t == b_t,
+                (Projection(a_p), Projection(b_p)) => a_p == b_p,
+                (Opaque(a_d, a_s), Opaque(b_d, b_s)) => a_d == b_d && a_s == b_s,
+                (Param(a_p), Param(b_p)) => a_p == b_p,
+                (Bound(a_d, a_b), Bound(b_d, b_b)) => a_d == b_d && a_b == b_b,
+                (Placeholder(a_p), Placeholder(b_p)) => a_p == b_p,
+                (Infer(a_t), Infer(b_t)) => a_t == b_t,
+                (Error(a_e), Error(b_e)) => a_e == b_e,
+                (Bool, Bool) | (Char, Char) | (Str, Str) | (Never, Never) => true,
+                _ => {
+                    debug_assert!(
+                        false,
+                        "This branch must be unreachable, maybe the match is missing an arm? self = self = {self:?}, other = {other:?}"
+                    );
+                    true
                 }
-                (&FnPtr(ref __self_0), &FnPtr(ref __arg_1_0)) => __self_0 == __arg_1_0,
-                (
-                    &Dynamic(ref __self_0, ref __self_1, ref self_repr),
-                    &Dynamic(ref __arg_1_0, ref __arg_1_1, ref arg_repr),
-                ) => __self_0 == __arg_1_0 && __self_1 == __arg_1_1 && self_repr == arg_repr,
-                (&Closure(ref __self_0, ref __self_1), &Closure(ref __arg_1_0, ref __arg_1_1)) => {
-                    __self_0 == __arg_1_0 && __self_1 == __arg_1_1
-                }
-                (
-                    &Generator(ref __self_0, ref __self_1, ref __self_2),
-                    &Generator(ref __arg_1_0, ref __arg_1_1, ref __arg_1_2),
-                ) => __self_0 == __arg_1_0 && __self_1 == __arg_1_1 && __self_2 == __arg_1_2,
-                (&GeneratorWitness(ref __self_0), &GeneratorWitness(ref __arg_1_0)) => {
-                    __self_0 == __arg_1_0
-                }
-                (&Tuple(ref __self_0), &Tuple(ref __arg_1_0)) => __self_0 == __arg_1_0,
-                (&Projection(ref __self_0), &Projection(ref __arg_1_0)) => __self_0 == __arg_1_0,
-                (&Opaque(ref __self_0, ref __self_1), &Opaque(ref __arg_1_0, ref __arg_1_1)) => {
-                    __self_0 == __arg_1_0 && __self_1 == __arg_1_1
-                }
-                (&Param(ref __self_0), &Param(ref __arg_1_0)) => __self_0 == __arg_1_0,
-                (&Bound(ref __self_0, ref __self_1), &Bound(ref __arg_1_0, ref __arg_1_1)) => {
-                    __self_0 == __arg_1_0 && __self_1 == __arg_1_1
-                }
-                (&Placeholder(ref __self_0), &Placeholder(ref __arg_1_0)) => __self_0 == __arg_1_0,
-                (&Infer(ref __self_0), &Infer(ref __arg_1_0)) => __self_0 == __arg_1_0,
-                (&Error(ref __self_0), &Error(ref __arg_1_0)) => __self_0 == __arg_1_0,
-                _ => true,
             }
-        } else {
-            false
-        }
     }
 }
 
@@ -366,7 +349,7 @@ impl<I: Interner> Eq for TyKind<I> {}
 impl<I: Interner> PartialOrd for TyKind<I> {
     #[inline]
     fn partial_cmp(&self, other: &TyKind<I>) -> Option<Ordering> {
-        Some(Ord::cmp(self, other))
+        Some(self.cmp(other))
     }
 }
 
@@ -374,213 +357,106 @@ fn partial_cmp(&self, other: &TyKind<I>) -> Option<Ordering> {
 impl<I: Interner> Ord for TyKind<I> {
     #[inline]
     fn cmp(&self, other: &TyKind<I>) -> Ordering {
-        let __self_vi = tykind_discriminant(self);
-        let __arg_1_vi = tykind_discriminant(other);
-        if __self_vi == __arg_1_vi {
-            match (&*self, &*other) {
-                (&Int(ref __self_0), &Int(ref __arg_1_0)) => Ord::cmp(__self_0, __arg_1_0),
-                (&Uint(ref __self_0), &Uint(ref __arg_1_0)) => Ord::cmp(__self_0, __arg_1_0),
-                (&Float(ref __self_0), &Float(ref __arg_1_0)) => Ord::cmp(__self_0, __arg_1_0),
-                (&Adt(ref __self_0, ref __self_1), &Adt(ref __arg_1_0, ref __arg_1_1)) => {
-                    match Ord::cmp(__self_0, __arg_1_0) {
-                        Ordering::Equal => Ord::cmp(__self_1, __arg_1_1),
-                        cmp => cmp,
-                    }
-                }
-                (&Foreign(ref __self_0), &Foreign(ref __arg_1_0)) => Ord::cmp(__self_0, __arg_1_0),
-                (&Array(ref __self_0, ref __self_1), &Array(ref __arg_1_0, ref __arg_1_1)) => {
-                    match Ord::cmp(__self_0, __arg_1_0) {
-                        Ordering::Equal => Ord::cmp(__self_1, __arg_1_1),
-                        cmp => cmp,
-                    }
-                }
-                (&Slice(ref __self_0), &Slice(ref __arg_1_0)) => Ord::cmp(__self_0, __arg_1_0),
-                (&RawPtr(ref __self_0), &RawPtr(ref __arg_1_0)) => Ord::cmp(__self_0, __arg_1_0),
-                (
-                    &Ref(ref __self_0, ref __self_1, ref __self_2),
-                    &Ref(ref __arg_1_0, ref __arg_1_1, ref __arg_1_2),
-                ) => match Ord::cmp(__self_0, __arg_1_0) {
-                    Ordering::Equal => match Ord::cmp(__self_1, __arg_1_1) {
-                        Ordering::Equal => Ord::cmp(__self_2, __arg_1_2),
-                        cmp => cmp,
-                    },
-                    cmp => cmp,
-                },
-                (&FnDef(ref __self_0, ref __self_1), &FnDef(ref __arg_1_0, ref __arg_1_1)) => {
-                    match Ord::cmp(__self_0, __arg_1_0) {
-                        Ordering::Equal => Ord::cmp(__self_1, __arg_1_1),
-                        cmp => cmp,
-                    }
+        tykind_discriminant(self).cmp(&tykind_discriminant(other)).then_with(|| {
+            match (self, other) {
+                (Int(a_i), Int(b_i)) => a_i.cmp(b_i),
+                (Uint(a_u), Uint(b_u)) => a_u.cmp(b_u),
+                (Float(a_f), Float(b_f)) => a_f.cmp(b_f),
+                (Adt(a_d, a_s), Adt(b_d, b_s)) => a_d.cmp(b_d).then_with(|| a_s.cmp(b_s)),
+                (Foreign(a_d), Foreign(b_d)) => a_d.cmp(b_d),
+                (Array(a_t, a_c), Array(b_t, b_c)) => a_t.cmp(b_t).then_with(|| a_c.cmp(b_c)),
+                (Slice(a_t), Slice(b_t)) => a_t.cmp(b_t),
+                (RawPtr(a_t), RawPtr(b_t)) => a_t.cmp(b_t),
+                (Ref(a_r, a_t, a_m), Ref(b_r, b_t, b_m)) => {
+                    a_r.cmp(b_r).then_with(|| a_t.cmp(b_t).then_with(|| a_m.cmp(b_m)))
                 }
-                (&FnPtr(ref __self_0), &FnPtr(ref __arg_1_0)) => Ord::cmp(__self_0, __arg_1_0),
-                (
-                    &Dynamic(ref __self_0, ref __self_1, ref self_repr),
-                    &Dynamic(ref __arg_1_0, ref __arg_1_1, ref arg_repr),
-                ) => match Ord::cmp(__self_0, __arg_1_0) {
-                    Ordering::Equal => match Ord::cmp(__self_1, __arg_1_1) {
-                        Ordering::Equal => Ord::cmp(self_repr, arg_repr),
-                        cmp => cmp,
-                    },
-                    cmp => cmp,
-                },
-                (&Closure(ref __self_0, ref __self_1), &Closure(ref __arg_1_0, ref __arg_1_1)) => {
-                    match Ord::cmp(__self_0, __arg_1_0) {
-                        Ordering::Equal => Ord::cmp(__self_1, __arg_1_1),
-                        cmp => cmp,
-                    }
+                (FnDef(a_d, a_s), FnDef(b_d, b_s)) => a_d.cmp(b_d).then_with(|| a_s.cmp(b_s)),
+                (FnPtr(a_s), FnPtr(b_s)) => a_s.cmp(b_s),
+                (Dynamic(a_p, a_r, a_repr), Dynamic(b_p, b_r, b_repr)) => {
+                    a_p.cmp(b_p).then_with(|| a_r.cmp(b_r).then_with(|| a_repr.cmp(b_repr)))
                 }
-                (
-                    &Generator(ref __self_0, ref __self_1, ref __self_2),
-                    &Generator(ref __arg_1_0, ref __arg_1_1, ref __arg_1_2),
-                ) => match Ord::cmp(__self_0, __arg_1_0) {
-                    Ordering::Equal => match Ord::cmp(__self_1, __arg_1_1) {
-                        Ordering::Equal => Ord::cmp(__self_2, __arg_1_2),
-                        cmp => cmp,
-                    },
-                    cmp => cmp,
-                },
-                (&GeneratorWitness(ref __self_0), &GeneratorWitness(ref __arg_1_0)) => {
-                    Ord::cmp(__self_0, __arg_1_0)
+                (Closure(a_p, a_s), Closure(b_p, b_s)) => a_p.cmp(b_p).then_with(|| a_s.cmp(b_s)),
+                (Generator(a_d, a_s, a_m), Generator(b_d, b_s, b_m)) => {
+                    a_d.cmp(b_d).then_with(|| a_s.cmp(b_s).then_with(|| a_m.cmp(b_m)))
                 }
-                (&Tuple(ref __self_0), &Tuple(ref __arg_1_0)) => Ord::cmp(__self_0, __arg_1_0),
-                (&Projection(ref __self_0), &Projection(ref __arg_1_0)) => {
-                    Ord::cmp(__self_0, __arg_1_0)
+                (GeneratorWitness(a_g), GeneratorWitness(b_g)) => a_g.cmp(b_g),
+                (Tuple(a_t), Tuple(b_t)) => a_t.cmp(b_t),
+                (Projection(a_p), Projection(b_p)) => a_p.cmp(b_p),
+                (Opaque(a_d, a_s), Opaque(b_d, b_s)) => a_d.cmp(b_d).then_with(|| a_s.cmp(b_s)),
+                (Param(a_p), Param(b_p)) => a_p.cmp(b_p),
+                (Bound(a_d, a_b), Bound(b_d, b_b)) => a_d.cmp(b_d).then_with(|| a_b.cmp(b_b)),
+                (Placeholder(a_p), Placeholder(b_p)) => a_p.cmp(b_p),
+                (Infer(a_t), Infer(b_t)) => a_t.cmp(b_t),
+                (Error(a_e), Error(b_e)) => a_e.cmp(b_e),
+                (Bool, Bool) | (Char, Char) | (Str, Str) | (Never, Never) => Ordering::Equal,
+                _ => {
+                    debug_assert!(false, "This branch must be unreachable, maybe the match is missing an arm? self = self = {self:?}, other = {other:?}");
+                    Ordering::Equal
                 }
-                (&Opaque(ref __self_0, ref __self_1), &Opaque(ref __arg_1_0, ref __arg_1_1)) => {
-                    match Ord::cmp(__self_0, __arg_1_0) {
-                        Ordering::Equal => Ord::cmp(__self_1, __arg_1_1),
-                        cmp => cmp,
-                    }
-                }
-                (&Param(ref __self_0), &Param(ref __arg_1_0)) => Ord::cmp(__self_0, __arg_1_0),
-                (&Bound(ref __self_0, ref __self_1), &Bound(ref __arg_1_0, ref __arg_1_1)) => {
-                    match Ord::cmp(__self_0, __arg_1_0) {
-                        Ordering::Equal => Ord::cmp(__self_1, __arg_1_1),
-                        cmp => cmp,
-                    }
-                }
-                (&Placeholder(ref __self_0), &Placeholder(ref __arg_1_0)) => {
-                    Ord::cmp(__self_0, __arg_1_0)
-                }
-                (&Infer(ref __self_0), &Infer(ref __arg_1_0)) => Ord::cmp(__self_0, __arg_1_0),
-                (&Error(ref __self_0), &Error(ref __arg_1_0)) => Ord::cmp(__self_0, __arg_1_0),
-                _ => Ordering::Equal,
             }
-        } else {
-            Ord::cmp(&__self_vi, &__arg_1_vi)
-        }
+        })
     }
 }
 
 // This is manually implemented because a derive would require `I: Hash`
 impl<I: Interner> hash::Hash for TyKind<I> {
     fn hash<__H: hash::Hasher>(&self, state: &mut __H) -> () {
-        match (&*self,) {
-            (&Int(ref __self_0),) => {
-                hash::Hash::hash(&tykind_discriminant(self), state);
-                hash::Hash::hash(__self_0, state)
-            }
-            (&Uint(ref __self_0),) => {
-                hash::Hash::hash(&tykind_discriminant(self), state);
-                hash::Hash::hash(__self_0, state)
-            }
-            (&Float(ref __self_0),) => {
-                hash::Hash::hash(&tykind_discriminant(self), state);
-                hash::Hash::hash(__self_0, state)
-            }
-            (&Adt(ref __self_0, ref __self_1),) => {
-                hash::Hash::hash(&tykind_discriminant(self), state);
-                hash::Hash::hash(__self_0, state);
-                hash::Hash::hash(__self_1, state)
-            }
-            (&Foreign(ref __self_0),) => {
-                hash::Hash::hash(&tykind_discriminant(self), state);
-                hash::Hash::hash(__self_0, state)
-            }
-            (&Array(ref __self_0, ref __self_1),) => {
-                hash::Hash::hash(&tykind_discriminant(self), state);
-                hash::Hash::hash(__self_0, state);
-                hash::Hash::hash(__self_1, state)
-            }
-            (&Slice(ref __self_0),) => {
-                hash::Hash::hash(&tykind_discriminant(self), state);
-                hash::Hash::hash(__self_0, state)
-            }
-            (&RawPtr(ref __self_0),) => {
-                hash::Hash::hash(&tykind_discriminant(self), state);
-                hash::Hash::hash(__self_0, state)
-            }
-            (&Ref(ref __self_0, ref __self_1, ref __self_2),) => {
-                hash::Hash::hash(&tykind_discriminant(self), state);
-                hash::Hash::hash(__self_0, state);
-                hash::Hash::hash(__self_1, state);
-                hash::Hash::hash(__self_2, state)
-            }
-            (&FnDef(ref __self_0, ref __self_1),) => {
-                hash::Hash::hash(&tykind_discriminant(self), state);
-                hash::Hash::hash(__self_0, state);
-                hash::Hash::hash(__self_1, state)
-            }
-            (&FnPtr(ref __self_0),) => {
-                hash::Hash::hash(&tykind_discriminant(self), state);
-                hash::Hash::hash(__self_0, state)
-            }
-            (&Dynamic(ref __self_0, ref __self_1, ref repr),) => {
-                hash::Hash::hash(&tykind_discriminant(self), state);
-                hash::Hash::hash(__self_0, state);
-                hash::Hash::hash(__self_1, state);
-                hash::Hash::hash(repr, state)
-            }
-            (&Closure(ref __self_0, ref __self_1),) => {
-                hash::Hash::hash(&tykind_discriminant(self), state);
-                hash::Hash::hash(__self_0, state);
-                hash::Hash::hash(__self_1, state)
-            }
-            (&Generator(ref __self_0, ref __self_1, ref __self_2),) => {
-                hash::Hash::hash(&tykind_discriminant(self), state);
-                hash::Hash::hash(__self_0, state);
-                hash::Hash::hash(__self_1, state);
-                hash::Hash::hash(__self_2, state)
-            }
-            (&GeneratorWitness(ref __self_0),) => {
-                hash::Hash::hash(&tykind_discriminant(self), state);
-                hash::Hash::hash(__self_0, state)
-            }
-            (&Tuple(ref __self_0),) => {
-                hash::Hash::hash(&tykind_discriminant(self), state);
-                hash::Hash::hash(__self_0, state)
-            }
-            (&Projection(ref __self_0),) => {
-                hash::Hash::hash(&tykind_discriminant(self), state);
-                hash::Hash::hash(__self_0, state)
-            }
-            (&Opaque(ref __self_0, ref __self_1),) => {
-                hash::Hash::hash(&tykind_discriminant(self), state);
-                hash::Hash::hash(__self_0, state);
-                hash::Hash::hash(__self_1, state)
-            }
-            (&Param(ref __self_0),) => {
-                hash::Hash::hash(&tykind_discriminant(self), state);
-                hash::Hash::hash(__self_0, state)
-            }
-            (&Bound(ref __self_0, ref __self_1),) => {
-                hash::Hash::hash(&tykind_discriminant(self), state);
-                hash::Hash::hash(__self_0, state);
-                hash::Hash::hash(__self_1, state)
-            }
-            (&Placeholder(ref __self_0),) => {
-                hash::Hash::hash(&tykind_discriminant(self), state);
-                hash::Hash::hash(__self_0, state)
-            }
-            (&Infer(ref __self_0),) => {
-                hash::Hash::hash(&tykind_discriminant(self), state);
-                hash::Hash::hash(__self_0, state)
+        tykind_discriminant(self).hash(state);
+        match self {
+            Int(i) => i.hash(state),
+            Uint(u) => u.hash(state),
+            Float(f) => f.hash(state),
+            Adt(d, s) => {
+                d.hash(state);
+                s.hash(state)
+            }
+            Foreign(d) => d.hash(state),
+            Array(t, c) => {
+                t.hash(state);
+                c.hash(state)
             }
-            (&Error(ref __self_0),) => {
-                hash::Hash::hash(&tykind_discriminant(self), state);
-                hash::Hash::hash(__self_0, state)
+            Slice(t) => t.hash(state),
+            RawPtr(t) => t.hash(state),
+            Ref(r, t, m) => {
+                r.hash(state);
+                t.hash(state);
+                m.hash(state)
+            }
+            FnDef(d, s) => {
+                d.hash(state);
+                s.hash(state)
+            }
+            FnPtr(s) => s.hash(state),
+            Dynamic(p, r, repr) => {
+                p.hash(state);
+                r.hash(state);
+                repr.hash(state)
+            }
+            Closure(d, s) => {
+                d.hash(state);
+                s.hash(state)
+            }
+            Generator(d, s, m) => {
+                d.hash(state);
+                s.hash(state);
+                m.hash(state)
+            }
+            GeneratorWitness(g) => g.hash(state),
+            Tuple(t) => t.hash(state),
+            Projection(p) => p.hash(state),
+            Opaque(d, s) => {
+                d.hash(state);
+                s.hash(state)
+            }
+            Param(p) => p.hash(state),
+            Bound(d, b) => {
+                d.hash(state);
+                b.hash(state)
             }
-            _ => hash::Hash::hash(&tykind_discriminant(self), state),
+            Placeholder(p) => p.hash(state),
+            Infer(t) => t.hash(state),
+            Error(e) => e.hash(state),
+            Bool | Char | Str | Never => (),
         }
     }
 }
@@ -588,37 +464,34 @@ fn hash<__H: hash::Hasher>(&self, state: &mut __H) -> () {
 // This is manually implemented because a derive would require `I: Debug`
 impl<I: Interner> fmt::Debug for TyKind<I> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        use std::fmt::*;
         match self {
-            Bool => Formatter::write_str(f, "Bool"),
-            Char => Formatter::write_str(f, "Char"),
-            Int(f0) => Formatter::debug_tuple_field1_finish(f, "Int", f0),
-            Uint(f0) => Formatter::debug_tuple_field1_finish(f, "Uint", f0),
-            Float(f0) => Formatter::debug_tuple_field1_finish(f, "Float", f0),
-            Adt(f0, f1) => Formatter::debug_tuple_field2_finish(f, "Adt", f0, f1),
-            Foreign(f0) => Formatter::debug_tuple_field1_finish(f, "Foreign", f0),
-            Str => Formatter::write_str(f, "Str"),
-            Array(f0, f1) => Formatter::debug_tuple_field2_finish(f, "Array", f0, f1),
-            Slice(f0) => Formatter::debug_tuple_field1_finish(f, "Slice", f0),
-            RawPtr(f0) => Formatter::debug_tuple_field1_finish(f, "RawPtr", f0),
-            Ref(f0, f1, f2) => Formatter::debug_tuple_field3_finish(f, "Ref", f0, f1, f2),
-            FnDef(f0, f1) => Formatter::debug_tuple_field2_finish(f, "FnDef", f0, f1),
-            FnPtr(f0) => Formatter::debug_tuple_field1_finish(f, "FnPtr", f0),
-            Dynamic(f0, f1, f2) => Formatter::debug_tuple_field3_finish(f, "Dynamic", f0, f1, f2),
-            Closure(f0, f1) => Formatter::debug_tuple_field2_finish(f, "Closure", f0, f1),
-            Generator(f0, f1, f2) => {
-                Formatter::debug_tuple_field3_finish(f, "Generator", f0, f1, f2)
-            }
-            GeneratorWitness(f0) => Formatter::debug_tuple_field1_finish(f, "GeneratorWitness", f0),
-            Never => Formatter::write_str(f, "Never"),
-            Tuple(f0) => Formatter::debug_tuple_field1_finish(f, "Tuple", f0),
-            Projection(f0) => Formatter::debug_tuple_field1_finish(f, "Projection", f0),
-            Opaque(f0, f1) => Formatter::debug_tuple_field2_finish(f, "Opaque", f0, f1),
-            Param(f0) => Formatter::debug_tuple_field1_finish(f, "Param", f0),
-            Bound(f0, f1) => Formatter::debug_tuple_field2_finish(f, "Bound", f0, f1),
-            Placeholder(f0) => Formatter::debug_tuple_field1_finish(f, "Placeholder", f0),
-            Infer(f0) => Formatter::debug_tuple_field1_finish(f, "Infer", f0),
-            TyKind::Error(f0) => Formatter::debug_tuple_field1_finish(f, "Error", f0),
+            Bool => f.write_str("Bool"),
+            Char => f.write_str("Char"),
+            Int(i) => f.debug_tuple_field1_finish("Int", i),
+            Uint(u) => f.debug_tuple_field1_finish("Uint", u),
+            Float(float) => f.debug_tuple_field1_finish("Float", float),
+            Adt(d, s) => f.debug_tuple_field2_finish("Adt", d, s),
+            Foreign(d) => f.debug_tuple_field1_finish("Foreign", d),
+            Str => f.write_str("Str"),
+            Array(t, c) => f.debug_tuple_field2_finish("Array", t, c),
+            Slice(t) => f.debug_tuple_field1_finish("Slice", t),
+            RawPtr(t) => f.debug_tuple_field1_finish("RawPtr", t),
+            Ref(r, t, m) => f.debug_tuple_field3_finish("Ref", r, t, m),
+            FnDef(d, s) => f.debug_tuple_field2_finish("FnDef", d, s),
+            FnPtr(s) => f.debug_tuple_field1_finish("FnPtr", s),
+            Dynamic(p, r, repr) => f.debug_tuple_field3_finish("Dynamic", p, r, repr),
+            Closure(d, s) => f.debug_tuple_field2_finish("Closure", d, s),
+            Generator(d, s, m) => f.debug_tuple_field3_finish("Generator", d, s, m),
+            GeneratorWitness(g) => f.debug_tuple_field1_finish("GeneratorWitness", g),
+            Never => f.write_str("Never"),
+            Tuple(t) => f.debug_tuple_field1_finish("Tuple", t),
+            Projection(p) => f.debug_tuple_field1_finish("Projection", p),
+            Opaque(d, s) => f.debug_tuple_field2_finish("Opaque", d, s),
+            Param(p) => f.debug_tuple_field1_finish("Param", p),
+            Bound(d, b) => f.debug_tuple_field2_finish("Bound", d, b),
+            Placeholder(p) => f.debug_tuple_field1_finish("Placeholder", p),
+            Infer(t) => f.debug_tuple_field1_finish("Infer", t),
+            TyKind::Error(e) => f.debug_tuple_field1_finish("Error", e),
         }
     }
 }
@@ -1091,12 +964,12 @@ impl<I: Interner> Copy for RegionKind<I>
 impl<I: Interner> Clone for RegionKind<I> {
     fn clone(&self) -> Self {
         match self {
-            ReEarlyBound(a) => ReEarlyBound(a.clone()),
-            ReLateBound(a, b) => ReLateBound(a.clone(), b.clone()),
-            ReFree(a) => ReFree(a.clone()),
+            ReEarlyBound(r) => ReEarlyBound(r.clone()),
+            ReLateBound(d, r) => ReLateBound(d.clone(), r.clone()),
+            ReFree(r) => ReFree(r.clone()),
             ReStatic => ReStatic,
-            ReVar(a) => ReVar(a.clone()),
-            RePlaceholder(a) => RePlaceholder(a.clone()),
+            ReVar(r) => ReVar(r.clone()),
+            RePlaceholder(r) => RePlaceholder(r.clone()),
             ReErased => ReErased,
         }
     }
@@ -1106,29 +979,23 @@ fn clone(&self) -> Self {
 impl<I: Interner> PartialEq for RegionKind<I> {
     #[inline]
     fn eq(&self, other: &RegionKind<I>) -> bool {
-        let __self_vi = regionkind_discriminant(self);
-        let __arg_1_vi = regionkind_discriminant(other);
-        if __self_vi == __arg_1_vi {
-            match (&*self, &*other) {
-                (&ReEarlyBound(ref __self_0), &ReEarlyBound(ref __arg_1_0)) => {
-                    __self_0 == __arg_1_0
+        regionkind_discriminant(self) == regionkind_discriminant(other)
+            && match (self, other) {
+                (ReEarlyBound(a_r), ReEarlyBound(b_r)) => a_r == b_r,
+                (ReLateBound(a_d, a_r), ReLateBound(b_d, b_r)) => a_d == b_d && a_r == b_r,
+                (ReFree(a_r), ReFree(b_r)) => a_r == b_r,
+                (ReStatic, ReStatic) => true,
+                (ReVar(a_r), ReVar(b_r)) => a_r == b_r,
+                (RePlaceholder(a_r), RePlaceholder(b_r)) => a_r == b_r,
+                (ReErased, ReErased) => true,
+                _ => {
+                    debug_assert!(
+                        false,
+                        "This branch must be unreachable, maybe the match is missing an arm? self = self = {self:?}, other = {other:?}"
+                    );
+                    true
                 }
-                (
-                    &ReLateBound(ref __self_0, ref __self_1),
-                    &ReLateBound(ref __arg_1_0, ref __arg_1_1),
-                ) => __self_0 == __arg_1_0 && __self_1 == __arg_1_1,
-                (&ReFree(ref __self_0), &ReFree(ref __arg_1_0)) => __self_0 == __arg_1_0,
-                (&ReStatic, &ReStatic) => true,
-                (&ReVar(ref __self_0), &ReVar(ref __arg_1_0)) => __self_0 == __arg_1_0,
-                (&RePlaceholder(ref __self_0), &RePlaceholder(ref __arg_1_0)) => {
-                    __self_0 == __arg_1_0
-                }
-                (&ReErased, &ReErased) => true,
-                _ => true,
             }
-        } else {
-            false
-        }
     }
 }
 
@@ -1139,7 +1006,7 @@ impl<I: Interner> Eq for RegionKind<I> {}
 impl<I: Interner> PartialOrd for RegionKind<I> {
     #[inline]
     fn partial_cmp(&self, other: &RegionKind<I>) -> Option<Ordering> {
-        Some(Ord::cmp(self, other))
+        Some(self.cmp(other))
     }
 }
 
@@ -1147,66 +1014,41 @@ fn partial_cmp(&self, other: &RegionKind<I>) -> Option<Ordering> {
 impl<I: Interner> Ord for RegionKind<I> {
     #[inline]
     fn cmp(&self, other: &RegionKind<I>) -> Ordering {
-        let __self_vi = regionkind_discriminant(self);
-        let __arg_1_vi = regionkind_discriminant(other);
-        if __self_vi == __arg_1_vi {
-            match (&*self, &*other) {
-                (&ReEarlyBound(ref __self_0), &ReEarlyBound(ref __arg_1_0)) => {
-                    Ord::cmp(__self_0, __arg_1_0)
+        regionkind_discriminant(self).cmp(&regionkind_discriminant(other)).then_with(|| {
+            match (self, other) {
+                (ReEarlyBound(a_r), ReEarlyBound(b_r)) => a_r.cmp(b_r),
+                (ReLateBound(a_d, a_r), ReLateBound(b_d, b_r)) => {
+                    a_d.cmp(b_d).then_with(|| a_r.cmp(b_r))
                 }
-                (
-                    &ReLateBound(ref __self_0, ref __self_1),
-                    &ReLateBound(ref __arg_1_0, ref __arg_1_1),
-                ) => match Ord::cmp(__self_0, __arg_1_0) {
-                    Ordering::Equal => Ord::cmp(__self_1, __arg_1_1),
-                    cmp => cmp,
-                },
-                (&ReFree(ref __self_0), &ReFree(ref __arg_1_0)) => Ord::cmp(__self_0, __arg_1_0),
-                (&ReStatic, &ReStatic) => Ordering::Equal,
-                (&ReVar(ref __self_0), &ReVar(ref __arg_1_0)) => Ord::cmp(__self_0, __arg_1_0),
-                (&RePlaceholder(ref __self_0), &RePlaceholder(ref __arg_1_0)) => {
-                    Ord::cmp(__self_0, __arg_1_0)
+                (ReFree(a_r), ReFree(b_r)) => a_r.cmp(b_r),
+                (ReStatic, ReStatic) => Ordering::Equal,
+                (ReVar(a_r), ReVar(b_r)) => a_r.cmp(b_r),
+                (RePlaceholder(a_r), RePlaceholder(b_r)) => a_r.cmp(b_r),
+                (ReErased, ReErased) => Ordering::Equal,
+                _ => {
+                    debug_assert!(false, "This branch must be unreachable, maybe the match is missing an arm? self = self = {self:?}, other = {other:?}");
+                    Ordering::Equal
                 }
-                (&ReErased, &ReErased) => Ordering::Equal,
-                _ => Ordering::Equal,
             }
-        } else {
-            Ord::cmp(&__self_vi, &__arg_1_vi)
-        }
+        })
     }
 }
 
 // This is manually implemented because a derive would require `I: Hash`
 impl<I: Interner> hash::Hash for RegionKind<I> {
-    fn hash<__H: hash::Hasher>(&self, state: &mut __H) -> () {
-        match (&*self,) {
-            (&ReEarlyBound(ref __self_0),) => {
-                hash::Hash::hash(&regionkind_discriminant(self), state);
-                hash::Hash::hash(__self_0, state)
-            }
-            (&ReLateBound(ref __self_0, ref __self_1),) => {
-                hash::Hash::hash(&regionkind_discriminant(self), state);
-                hash::Hash::hash(__self_0, state);
-                hash::Hash::hash(__self_1, state)
-            }
-            (&ReFree(ref __self_0),) => {
-                hash::Hash::hash(&regionkind_discriminant(self), state);
-                hash::Hash::hash(__self_0, state)
-            }
-            (&ReStatic,) => {
-                hash::Hash::hash(&regionkind_discriminant(self), state);
-            }
-            (&ReVar(ref __self_0),) => {
-                hash::Hash::hash(&regionkind_discriminant(self), state);
-                hash::Hash::hash(__self_0, state)
-            }
-            (&RePlaceholder(ref __self_0),) => {
-                hash::Hash::hash(&regionkind_discriminant(self), state);
-                hash::Hash::hash(__self_0, state)
-            }
-            (&ReErased,) => {
-                hash::Hash::hash(&regionkind_discriminant(self), state);
-            }
+    fn hash<H: hash::Hasher>(&self, state: &mut H) -> () {
+        regionkind_discriminant(self).hash(state);
+        match self {
+            ReEarlyBound(r) => r.hash(state),
+            ReLateBound(d, r) => {
+                d.hash(state);
+                r.hash(state)
+            }
+            ReFree(r) => r.hash(state),
+            ReStatic => (),
+            ReVar(r) => r.hash(state),
+            RePlaceholder(r) => r.hash(state),
+            ReErased => (),
         }
     }
 }
@@ -1215,21 +1057,21 @@ fn hash<__H: hash::Hasher>(&self, state: &mut __H) -> () {
 impl<I: Interner> fmt::Debug for RegionKind<I> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         match self {
-            ReEarlyBound(ref data) => write!(f, "ReEarlyBound({:?})", data),
+            ReEarlyBound(data) => write!(f, "ReEarlyBound({:?})", data),
 
-            ReLateBound(binder_id, ref bound_region) => {
+            ReLateBound(binder_id, bound_region) => {
                 write!(f, "ReLateBound({:?}, {:?})", binder_id, bound_region)
             }
 
-            ReFree(ref fr) => fr.fmt(f),
+            ReFree(fr) => fr.fmt(f),
 
-            ReStatic => write!(f, "ReStatic"),
+            ReStatic => f.write_str("ReStatic"),
 
-            ReVar(ref vid) => vid.fmt(f),
+            ReVar(vid) => vid.fmt(f),
 
             RePlaceholder(placeholder) => write!(f, "RePlaceholder({:?})", placeholder),
 
-            ReErased => write!(f, "ReErased"),
+            ReErased => f.write_str("ReErased"),
         }
     }
 }
@@ -1317,18 +1159,18 @@ fn hash_stable(
             ReErased | ReStatic => {
                 // No variant fields to hash for these ...
             }
-            ReLateBound(db, br) => {
-                db.hash_stable(hcx, hasher);
-                br.hash_stable(hcx, hasher);
+            ReLateBound(dr) => {
+                d.hash_stable(hcx, hasher);
+                r.hash_stable(hcx, hasher);
             }
-            ReEarlyBound(eb) => {
-                eb.hash_stable(hcx, hasher);
+            ReEarlyBound(r) => {
+                r.hash_stable(hcx, hasher);
             }
-            ReFree(ref free_region) => {
-                free_region.hash_stable(hcx, hasher);
+            ReFree(r) => {
+                r.hash_stable(hcx, hasher);
             }
-            RePlaceholder(p) => {
-                p.hash_stable(hcx, hasher);
+            RePlaceholder(r) => {
+                r.hash_stable(hcx, hasher);
             }
             ReVar(_) => {
                 panic!("region variables should not be hashed: {self:?}")
diff --git a/compiler/rustc_type_ir/src/ty_info.rs b/compiler/rustc_type_ir/src/ty_info.rs
new file mode 100644 (file)
index 0000000..4e5d424
--- /dev/null
@@ -0,0 +1,122 @@
+use std::{
+    cmp::Ordering,
+    hash::{Hash, Hasher},
+    ops::Deref,
+};
+
+use rustc_data_structures::{
+    fingerprint::Fingerprint,
+    stable_hasher::{HashStable, StableHasher},
+};
+
+use crate::{DebruijnIndex, TypeFlags};
+
+/// A helper type that you can wrap round your own type in order to automatically
+/// cache the stable hash, type flags and debruijn index on creation and
+/// not recompute it whenever the information is needed.
+/// This is only done in incremental mode. You can also opt out of caching by using
+/// StableHash::ZERO for the hash, in which case the hash gets computed each time.
+/// This is useful if you have values that you intern but never (can?) use for stable
+/// hashing.
+#[derive(Copy, Clone)]
+pub struct WithCachedTypeInfo<T> {
+    pub internee: T,
+    pub stable_hash: Fingerprint,
+
+    /// This field provides fast access to information that is also contained
+    /// in `kind`.
+    ///
+    /// This field shouldn't be used directly and may be removed in the future.
+    /// Use `Ty::flags()` instead.
+    pub flags: TypeFlags,
+
+    /// This field provides fast access to information that is also contained
+    /// in `kind`.
+    ///
+    /// This is a kind of confusing thing: it stores the smallest
+    /// binder such that
+    ///
+    /// (a) the binder itself captures nothing but
+    /// (b) all the late-bound things within the type are captured
+    ///     by some sub-binder.
+    ///
+    /// So, for a type without any late-bound things, like `u32`, this
+    /// will be *innermost*, because that is the innermost binder that
+    /// captures nothing. But for a type `&'D u32`, where `'D` is a
+    /// late-bound region with De Bruijn index `D`, this would be `D + 1`
+    /// -- the binder itself does not capture `D`, but `D` is captured
+    /// by an inner binder.
+    ///
+    /// We call this concept an "exclusive" binder `D` because all
+    /// De Bruijn indices within the type are contained within `0..D`
+    /// (exclusive).
+    pub outer_exclusive_binder: DebruijnIndex,
+}
+
+impl<T: PartialEq> PartialEq for WithCachedTypeInfo<T> {
+    #[inline]
+    fn eq(&self, other: &Self) -> bool {
+        self.internee.eq(&other.internee)
+    }
+}
+
+impl<T: Eq> Eq for WithCachedTypeInfo<T> {}
+
+impl<T: Ord> PartialOrd for WithCachedTypeInfo<T> {
+    fn partial_cmp(&self, other: &WithCachedTypeInfo<T>) -> Option<Ordering> {
+        Some(self.internee.cmp(&other.internee))
+    }
+}
+
+impl<T: Ord> Ord for WithCachedTypeInfo<T> {
+    fn cmp(&self, other: &WithCachedTypeInfo<T>) -> Ordering {
+        self.internee.cmp(&other.internee)
+    }
+}
+
+impl<T> Deref for WithCachedTypeInfo<T> {
+    type Target = T;
+
+    #[inline]
+    fn deref(&self) -> &T {
+        &self.internee
+    }
+}
+
+impl<T: Hash> Hash for WithCachedTypeInfo<T> {
+    #[inline]
+    fn hash<H: Hasher>(&self, s: &mut H) {
+        if self.stable_hash != Fingerprint::ZERO {
+            self.stable_hash.hash(s)
+        } else {
+            self.internee.hash(s)
+        }
+    }
+}
+
+impl<T: HashStable<CTX>, CTX> HashStable<CTX> for WithCachedTypeInfo<T> {
+    fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) {
+        if self.stable_hash == Fingerprint::ZERO || cfg!(debug_assertions) {
+            // No cached hash available. This can only mean that incremental is disabled.
+            // We don't cache stable hashes in non-incremental mode, because they are used
+            // so rarely that the performance actually suffers.
+
+            // We need to build the hash as if we cached it and then hash that hash, as
+            // otherwise the hashes will differ between cached and non-cached mode.
+            let stable_hash: Fingerprint = {
+                let mut hasher = StableHasher::new();
+                self.internee.hash_stable(hcx, &mut hasher);
+                hasher.finish()
+            };
+            if cfg!(debug_assertions) && self.stable_hash != Fingerprint::ZERO {
+                assert_eq!(
+                    stable_hash, self.stable_hash,
+                    "cached stable hash does not match freshly computed stable hash"
+                );
+            }
+            stable_hash.hash_stable(hcx, hasher);
+        } else {
+            self.stable_hash.hash_stable(hcx, hasher);
+        }
+    }
+}
index c94a27b12a3a73661f7295f57a79f152ba3b9c3c..5e1d2f2e314ff904173d04c224797cd2b017b5f2 100644 (file)
@@ -35,9 +35,6 @@ changelog-seen = 2
 # Unless you're developing for a target where Rust CI doesn't build a compiler
 # toolchain or changing LLVM locally, you probably want to set this to true.
 #
-# This is false by default so that distributions don't unexpectedly download
-# LLVM from the internet.
-#
 # All tier 1 targets are currently supported; set this to `"if-available"` if
 # you are not sure whether you're on a tier 1 target.
 #
@@ -45,7 +42,9 @@ changelog-seen = 2
 #
 # Note that many of the LLVM options are not currently supported for
 # downloading. Currently only the "assertions" option can be toggled.
-#download-ci-llvm = false
+#
+# Defaults to "if-available" when `channel = "dev"` and "false" otherwise.
+#download-ci-llvm = "if-available"
 
 # Indicates whether LLVM rebuild should be skipped when running bootstrap. If
 # this is `false` then the compiler's LLVM will be rebuilt whenever the built
@@ -255,6 +254,16 @@ changelog-seen = 2
 # Defaults to the Python interpreter used to execute x.py
 #python = "python"
 
+# The path to the REUSE executable to use. Note that REUSE is not required in
+# most cases, as our tooling relies on a cached (and shrinked) copy of the
+# REUSE output present in the git repository and in our source tarballs.
+#
+# REUSE is only needed if your changes caused the overral licensing of the
+# repository to change, and the cached copy has to be regenerated.
+#
+# Defaults to the "reuse" command in the system path.
+#reuse = "reuse"
+
 # Force Cargo to check that Cargo.lock describes the precise dependency
 # set that all the Cargo.toml files create, instead of updating it.
 #locked-deps = false
index 55f6138cd0f31407217fd4ef17fb391a5f55c80d..e54880e8652305b7f173d08f48aae0b18276212d 100644 (file)
@@ -25,6 +25,10 @@ impl<T, A: Allocator> IntoIter<T, A> {
     pub(super) fn new(inner: VecDeque<T, A>) -> Self {
         IntoIter { inner }
     }
+
+    pub(super) fn into_vecdeque(self) -> VecDeque<T, A> {
+        self.inner
+    }
 }
 
 #[stable(feature = "collection_debug", since = "1.17.0")]
index 86d77182bccee7800cf0875f1436c68eab4d226b..4b9bd74d3924f49a93abb03a3e56b645566de6cf 100644 (file)
 
 mod spec_extend;
 
+use self::spec_from_iter::SpecFromIter;
+
+mod spec_from_iter;
+
 #[cfg(test)]
 mod tests;
 
@@ -566,10 +570,9 @@ impl<T, A: Allocator> VecDeque<T, A> {
     ///
     /// let deque: VecDeque<u32> = VecDeque::new();
     /// ```
-    // FIXME: This should probably be const
     #[inline]
     #[unstable(feature = "allocator_api", issue = "32838")]
-    pub fn new_in(alloc: A) -> VecDeque<T, A> {
+    pub const fn new_in(alloc: A) -> VecDeque<T, A> {
         VecDeque { head: 0, len: 0, buf: RawVec::new_in(alloc) }
     }
 
@@ -587,6 +590,38 @@ pub fn with_capacity_in(capacity: usize, alloc: A) -> VecDeque<T, A> {
         VecDeque { head: 0, len: 0, buf: RawVec::with_capacity_in(capacity, alloc) }
     }
 
+    /// Creates a `VecDeque` from a raw allocation, when the initialized
+    /// part of that allocation forms a *contiguous* subslice thereof.
+    ///
+    /// For use by `vec::IntoIter::into_vecdeque`
+    ///
+    /// # Safety
+    ///
+    /// All the usual requirements on the allocated memory like in
+    /// `Vec::from_raw_parts_in`, but takes a *range* of elements that are
+    /// initialized rather than only supporting `0..len`.  Requires that
+    /// `initialized.start` â‰¤ `initialized.end` â‰¤ `capacity`.
+    #[inline]
+    pub(crate) unsafe fn from_contiguous_raw_parts_in(
+        ptr: *mut T,
+        initialized: Range<usize>,
+        capacity: usize,
+        alloc: A,
+    ) -> Self {
+        debug_assert!(initialized.start <= initialized.end);
+        debug_assert!(initialized.end <= capacity);
+
+        // SAFETY: Our safety precondition guarantees the range length won't wrap,
+        // and that the allocation is valid for use in `RawVec`.
+        unsafe {
+            VecDeque {
+                head: initialized.start,
+                len: initialized.end.unchecked_sub(initialized.start),
+                buf: RawVec::from_raw_parts_in(ptr, capacity, alloc),
+            }
+        }
+    }
+
     /// Provides a reference to the element at the given index.
     ///
     /// Element at index 0 is the front of the queue.
@@ -2152,7 +2187,7 @@ pub fn make_contiguous(&mut self) -> &mut [T] {
 
             self.head = tail;
         } else {
-            // Â´free` is smaller than both `head_len` and `tail_len`.
+            // `free` is smaller than both `head_len` and `tail_len`.
             // the general algorithm for this first moves the slices
             // right next to each other and then uses `slice::rotate`
             // to rotate them into place:
@@ -2701,11 +2736,7 @@ fn index_mut(&mut self, index: usize) -> &mut T {
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<T> FromIterator<T> for VecDeque<T> {
     fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> VecDeque<T> {
-        let iterator = iter.into_iter();
-        let (lower, _) = iterator.size_hint();
-        let mut deq = VecDeque::with_capacity(lower);
-        deq.extend(iterator);
-        deq
+        SpecFromIter::spec_from_iter(iter.into_iter())
     }
 }
 
@@ -2792,6 +2823,7 @@ impl<T, A: Allocator> From<Vec<T, A>> for VecDeque<T, A> {
     /// In its current implementation, this is a very cheap
     /// conversion. This isn't yet a guarantee though, and
     /// shouldn't be relied on.
+    #[inline]
     fn from(other: Vec<T, A>) -> Self {
         let (ptr, len, cap, alloc) = other.into_raw_parts_with_alloc();
         Self { head: 0, len, buf: unsafe { RawVec::from_raw_parts_in(ptr, cap, alloc) } }
diff --git a/library/alloc/src/collections/vec_deque/spec_from_iter.rs b/library/alloc/src/collections/vec_deque/spec_from_iter.rs
new file mode 100644 (file)
index 0000000..7650492
--- /dev/null
@@ -0,0 +1,33 @@
+use super::{IntoIter, VecDeque};
+
+/// Specialization trait used for `VecDeque::from_iter`
+pub(super) trait SpecFromIter<T, I> {
+    fn spec_from_iter(iter: I) -> Self;
+}
+
+impl<T, I> SpecFromIter<T, I> for VecDeque<T>
+where
+    I: Iterator<Item = T>,
+{
+    default fn spec_from_iter(iterator: I) -> Self {
+        // Since converting is O(1) now, just re-use the `Vec` logic for
+        // anything where we can't do something extra-special for `VecDeque`,
+        // especially as that could save us some monomorphiziation work
+        // if one uses the same iterators (like slice ones) with both.
+        crate::vec::Vec::from_iter(iterator).into()
+    }
+}
+
+impl<T> SpecFromIter<T, crate::vec::IntoIter<T>> for VecDeque<T> {
+    #[inline]
+    fn spec_from_iter(iterator: crate::vec::IntoIter<T>) -> Self {
+        iterator.into_vecdeque()
+    }
+}
+
+impl<T> SpecFromIter<T, IntoIter<T>> for VecDeque<T> {
+    #[inline]
+    fn spec_from_iter(iterator: IntoIter<T>) -> Self {
+        iterator.into_vecdeque()
+    }
+}
index 02cc7691a82db6af72b99fd9c735e17656ea048b..6bcde6d899ce81776fe8dc55c20d528daec84472 100644 (file)
@@ -1,6 +1,8 @@
 #[cfg(not(no_global_oom_handling))]
 use super::AsVecIntoIter;
 use crate::alloc::{Allocator, Global};
+#[cfg(not(no_global_oom_handling))]
+use crate::collections::VecDeque;
 use crate::raw_vec::RawVec;
 use core::array;
 use core::fmt;
@@ -132,6 +134,33 @@ pub(super) fn forget_allocation_drop_remaining(&mut self) {
     pub(crate) fn forget_remaining_elements(&mut self) {
         self.ptr = self.end;
     }
+
+    #[cfg(not(no_global_oom_handling))]
+    #[inline]
+    pub(crate) fn into_vecdeque(self) -> VecDeque<T, A> {
+        // Keep our `Drop` impl from dropping the elements and the allocator
+        let mut this = ManuallyDrop::new(self);
+
+        // SAFETY: This allocation originally came from a `Vec`, so it passes
+        // all those checks.  We have `this.buf` â‰¤ `this.ptr` â‰¤ `this.end`,
+        // so the `sub_ptr`s below cannot wrap, and will produce a well-formed
+        // range.  `end` â‰¤ `buf + cap`, so the range will be in-bounds.
+        // Taking `alloc` is ok because nothing else is going to look at it,
+        // since our `Drop` impl isn't going to run so there's no more code.
+        unsafe {
+            let buf = this.buf.as_ptr();
+            let initialized = if T::IS_ZST {
+                // All the pointers are the same for ZSTs, so it's fine to
+                // say that they're all at the beginning of the "allocation".
+                0..this.len()
+            } else {
+                this.ptr.sub_ptr(buf)..this.end.sub_ptr(buf)
+            };
+            let cap = this.cap;
+            let alloc = ManuallyDrop::take(&mut this.alloc);
+            VecDeque::from_contiguous_raw_parts_in(buf, initialized, cap, alloc)
+        }
+    }
 }
 
 #[stable(feature = "vec_intoiter_as_ref", since = "1.46.0")]
index e147af2ce39c68f905601bfc9c2c66e1b8c1687f..ba34ab6800fad4cdd9f6e8be14a63eca335aac17 100644 (file)
@@ -1070,7 +1070,8 @@ pub fn shrink_to(&mut self, min_capacity: usize) {
 
     /// Converts the vector into [`Box<[T]>`][owned slice].
     ///
-    /// Note that this will drop any excess capacity.
+    /// If the vector has excess capacity, its items will be moved into a
+    /// newly-allocated buffer with exactly the right capacity.
     ///
     /// [owned slice]: Box
     ///
@@ -3223,6 +3224,14 @@ impl<T, A: Allocator> From<Vec<T, A>> for Box<[T], A> {
     /// ```
     /// assert_eq!(Box::from(vec![1, 2, 3]), vec![1, 2, 3].into_boxed_slice());
     /// ```
+    ///
+    /// Any excess capacity is removed:
+    /// ```
+    /// let mut vec = Vec::with_capacity(10);
+    /// vec.extend([1, 2, 3]);
+    ///
+    /// assert_eq!(Box::from(vec), vec![1, 2, 3].into_boxed_slice());
+    /// ```
     fn from(v: Vec<T, A>) -> Self {
         v.into_boxed_slice()
     }
index d04de5a074b7fafa3d186d6762a336141c133b2b..0b8f5281b785cab4af103238d5125bc1660f358c 100644 (file)
@@ -1736,3 +1736,39 @@ fn test_resize_keeps_reserved_space_from_item() {
     d.resize(1, v);
     assert_eq!(d[0].capacity(), 1234);
 }
+
+#[test]
+fn test_collect_from_into_iter_keeps_allocation() {
+    let mut v = Vec::with_capacity(13);
+    v.extend(0..7);
+    check(v.as_ptr(), v.last().unwrap(), v.into_iter());
+
+    let mut v = VecDeque::with_capacity(13);
+    v.extend(0..7);
+    check(&v[0], &v[v.len() - 1], v.into_iter());
+
+    fn check(buf: *const i32, last: *const i32, mut it: impl Iterator<Item = i32>) {
+        assert_eq!(it.next(), Some(0));
+        assert_eq!(it.next(), Some(1));
+
+        let mut v: VecDeque<i32> = it.collect();
+        assert_eq!(v.capacity(), 13);
+        assert_eq!(v.as_slices().0.as_ptr(), buf.wrapping_add(2));
+        assert_eq!(&v[v.len() - 1] as *const _, last);
+
+        assert_eq!(v.as_slices(), ([2, 3, 4, 5, 6].as_slice(), [].as_slice()));
+        v.push_front(7);
+        assert_eq!(v.as_slices(), ([7, 2, 3, 4, 5, 6].as_slice(), [].as_slice()));
+        v.push_front(8);
+        assert_eq!(v.as_slices(), ([8, 7, 2, 3, 4, 5, 6].as_slice(), [].as_slice()));
+
+        // Now that we've adding thing in place of the two that we removed from
+        // the front of the iterator, we're back to matching the buffer pointer.
+        assert_eq!(v.as_slices().0.as_ptr(), buf);
+        assert_eq!(&v[v.len() - 1] as *const _, last);
+
+        v.push_front(9);
+        assert_eq!(v.as_slices(), ([9].as_slice(), [8, 7, 2, 3, 4, 5, 6].as_slice()));
+        assert_eq!(v.capacity(), 13);
+    }
+}
index 06dca7e59a2a696088e76775aa814bd14299b9c6..398437d9a023dcb7e386d669e30615f88d869cd7 100644 (file)
@@ -176,7 +176,6 @@ pub struct AssertParamIsCopy<T: Copy + ?Sized> {
 /// are implemented in `traits::SelectionContext::copy_clone_conditions()`
 /// in `rustc_trait_selection`.
 mod impls {
-
     use super::Clone;
 
     macro_rules! impl_clone {
@@ -185,7 +184,7 @@ macro_rules! impl_clone {
                 #[stable(feature = "rust1", since = "1.0.0")]
                 #[rustc_const_unstable(feature = "const_clone", issue = "91805")]
                 impl const Clone for $t {
-                    #[inline]
+                    #[inline(always)]
                     fn clone(&self) -> Self {
                         *self
                     }
@@ -213,7 +212,7 @@ fn clone(&self) -> Self {
     #[stable(feature = "rust1", since = "1.0.0")]
     #[rustc_const_unstable(feature = "const_clone", issue = "91805")]
     impl<T: ?Sized> const Clone for *const T {
-        #[inline]
+        #[inline(always)]
         fn clone(&self) -> Self {
             *self
         }
@@ -222,7 +221,7 @@ fn clone(&self) -> Self {
     #[stable(feature = "rust1", since = "1.0.0")]
     #[rustc_const_unstable(feature = "const_clone", issue = "91805")]
     impl<T: ?Sized> const Clone for *mut T {
-        #[inline]
+        #[inline(always)]
         fn clone(&self) -> Self {
             *self
         }
@@ -232,7 +231,7 @@ fn clone(&self) -> Self {
     #[stable(feature = "rust1", since = "1.0.0")]
     #[rustc_const_unstable(feature = "const_clone", issue = "91805")]
     impl<T: ?Sized> const Clone for &T {
-        #[inline]
+        #[inline(always)]
         #[rustc_diagnostic_item = "noop_method_clone"]
         fn clone(&self) -> Self {
             *self
index 5db5cbfc3dfdde2c6349e3fc145c05f29f4d6fdb..949896e57480677b8192509782d00380558c9ed9 100644 (file)
@@ -29,8 +29,7 @@
 
 use self::Ordering::*;
 
-/// Trait for equality comparisons which are [partial equivalence
-/// relations](https://en.wikipedia.org/wiki/Partial_equivalence_relation).
+/// Trait for equality comparisons.
 ///
 /// `x.eq(y)` can also be written `x == y`, and `x.ne(y)` can be written `x != y`.
 /// We use the easier-to-read infix notation in the remainder of this documentation.
@@ -38,6 +37,8 @@
 /// This trait allows for partial equality, for types that do not have a full
 /// equivalence relation. For example, in floating point numbers `NaN != NaN`,
 /// so floating point types implement `PartialEq` but not [`trait@Eq`].
+/// Formally speaking, when `Rhs == Self`, this trait corresponds to a [partial equivalence
+/// relation](https://en.wikipedia.org/wiki/Partial_equivalence_relation).
 ///
 /// Implementations must ensure that `eq` and `ne` are consistent with each other:
 ///
index 33493964bad2ed8dfb30402444ac8a56041778c8..f95b880df34d37b3b3fc2a8b920bcde4bf6186c5 100644 (file)
@@ -99,7 +99,7 @@
 /// ```
 #[stable(feature = "convert_id", since = "1.33.0")]
 #[rustc_const_stable(feature = "const_identity", since = "1.33.0")]
-#[inline]
+#[inline(always)]
 pub const fn identity<T>(x: T) -> T {
     x
 }
@@ -789,6 +789,7 @@ fn try_from(value: U) -> Result<Self, Self::Error> {
 
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<T> AsRef<[T]> for [T] {
+    #[inline(always)]
     fn as_ref(&self) -> &[T] {
         self
     }
@@ -796,6 +797,7 @@ fn as_ref(&self) -> &[T] {
 
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<T> AsMut<[T]> for [T] {
+    #[inline(always)]
     fn as_mut(&mut self) -> &mut [T] {
         self
     }
@@ -803,7 +805,7 @@ fn as_mut(&mut self) -> &mut [T] {
 
 #[stable(feature = "rust1", since = "1.0.0")]
 impl AsRef<str> for str {
-    #[inline]
+    #[inline(always)]
     fn as_ref(&self) -> &str {
         self
     }
@@ -811,7 +813,7 @@ fn as_ref(&self) -> &str {
 
 #[stable(feature = "as_mut_str_for_str", since = "1.51.0")]
 impl AsMut<str> for str {
-    #[inline]
+    #[inline(always)]
     fn as_mut(&mut self) -> &mut str {
         self
     }
index 4fa5d129bc6af6ccfa6853c8cc16cf76ea1839dc..9c0d7e9a1e89e25014d5d42809caecd70c485a7f 100644 (file)
@@ -49,7 +49,7 @@ impl const From<$Small> for $Large {
             // Rustdocs on the impl block show a "[+] show undocumented items" toggle.
             // Rustdocs on functions do not.
             #[doc = $doc]
-            #[inline]
+            #[inline(always)]
             fn from(small: $Small) -> Self {
                 small as Self
             }
index f2b961d62e00c8149750785c3792cdf94924ce1d..2a8e12fd4cf60fcc2bbc8aa749c500a6229f009c 100644 (file)
@@ -44,7 +44,7 @@
 ///    non-Send/Sync as well, and we don't want that.
 ///
 /// It also simplifies the HIR lowering of `.await`.
-#[cfg_attr(not(bootstrap), lang = "ResumeTy")]
+// FIXME(swatinem): This type can be removed when bumping the bootstrap compiler
 #[doc(hidden)]
 #[unstable(feature = "gen_future", issue = "50547")]
 #[derive(Debug, Copy, Clone)]
@@ -61,6 +61,7 @@ unsafe impl Sync for ResumeTy {}
 /// This function returns a `GenFuture` underneath, but hides it in `impl Trait` to give
 /// better error messages (`impl Future` rather than `GenFuture<[closure.....]>`).
 // This is `const` to avoid extra errors after we recover from `const async fn`
+// FIXME(swatinem): This fn can be removed when bumping the bootstrap compiler
 #[cfg_attr(bootstrap, lang = "from_generator")]
 #[doc(hidden)]
 #[unstable(feature = "gen_future", issue = "50547")]
@@ -102,7 +103,8 @@ fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
     GenFuture(gen)
 }
 
-#[lang = "get_context"]
+// FIXME(swatinem): This fn can be removed when bumping the bootstrap compiler
+#[cfg_attr(bootstrap, lang = "get_context")]
 #[doc(hidden)]
 #[unstable(feature = "gen_future", issue = "50547")]
 #[must_use]
@@ -113,6 +115,10 @@ pub unsafe fn get_context<'a, 'b>(cx: ResumeTy) -> &'a mut Context<'b> {
     unsafe { &mut *cx.0.as_ptr().cast() }
 }
 
+// FIXME(swatinem): This fn is currently needed to work around shortcomings
+// in type and lifetime inference.
+// See the comment at the bottom of `LoweringContext::make_async_expr` and
+// <https://github.com/rust-lang/rust/issues/104826>.
 #[cfg_attr(not(bootstrap), lang = "identity_future")]
 #[doc(hidden)]
 #[unstable(feature = "gen_future", issue = "50547")]
index c53175ba4f3f0f7bb23c701eda24d79abfae5926..e8d724ab1ef4eed662ac5ab2810878e6ee8e2904 100644 (file)
 /// ```
 ///
 /// [`thread::yield_now`]: ../../std/thread/fn.yield_now.html
-#[inline]
+#[inline(always)]
 #[stable(feature = "renamed_spin_loop", since = "1.49.0")]
 pub fn spin_loop() {
     #[cfg(target_arch = "x86")]
@@ -345,6 +345,7 @@ pub const fn black_box<T>(dummy: T) -> T {
 #[unstable(feature = "hint_must_use", issue = "94745")]
 #[rustc_const_unstable(feature = "hint_must_use", issue = "94745")]
 #[must_use] // <-- :)
+#[inline(always)]
 pub const fn must_use<T>(value: T) -> T {
     value
 }
index dc69bf4df595e9f68d216b07017f124fd369390a..fd8d25ce1a55e3b2280652cbf9bf2ac593edf4fd 100644 (file)
@@ -20,7 +20,7 @@
 /// #![feature(iter_repeat_n)]
 /// use std::iter;
 ///
-/// // four of the the number four:
+/// // four of the number four:
 /// let mut four_fours = iter::repeat_n(4, 4);
 ///
 /// assert_eq!(Some(4), four_fours.next());
index 84d83ee39699fe1841149b00e0c929389a1a7bc3..e31669b3924202db05ee2cceb8289ceae1075105 100644 (file)
 /// [`sum()`]: Iterator::sum
 /// [`FromIterator`]: iter::FromIterator
 #[stable(feature = "iter_arith_traits", since = "1.12.0")]
+#[rustc_on_unimplemented(
+    message = "a value of type `{Self}` cannot be made by summing an iterator over elements of type `{A}`",
+    label = "value of type `{Self}` cannot be made by summing a `std::iter::Iterator<Item={A}>`"
+)]
 pub trait Sum<A = Self>: Sized {
     /// Method which takes an iterator and generates `Self` from the elements by
     /// "summing up" the items.
@@ -27,6 +31,10 @@ pub trait Sum<A = Self>: Sized {
 /// [`product()`]: Iterator::product
 /// [`FromIterator`]: iter::FromIterator
 #[stable(feature = "iter_arith_traits", since = "1.12.0")]
+#[rustc_on_unimplemented(
+    message = "a value of type `{Self}` cannot be made by multiplying all elements of type `{A}` from an iterator",
+    label = "value of type `{Self}` cannot be made by multiplying all elements from a `std::iter::Iterator<Item={A}>`"
+)]
 pub trait Product<A = Self>: Sized {
     /// Method which takes an iterator and generates `Self` from the elements by
     /// multiplying the items.
index c20ca69a1c6f1dd67b6e8b68c372fd1c8e62d991..f29cd357d6bfd5218ab7489a3d40148b184d8231 100644 (file)
@@ -1546,6 +1546,18 @@ macro_rules! trace_macros {
         /* compiler built-in */
     }
 
+    /// Unstable placeholder for type ascription.
+    #[rustc_builtin_macro]
+    #[unstable(
+        feature = "type_ascription",
+        issue = "23416",
+        reason = "placeholder syntax for type ascription"
+    )]
+    #[cfg(not(bootstrap))]
+    pub macro type_ascribe($expr:expr, $ty:ty) {
+        /* compiler built-in */
+    }
+
     /// Unstable implementation detail of the `rustc` compiler, do not use.
     #[rustc_builtin_macro]
     #[stable(feature = "rust1", since = "1.0.0")]
index b2328b001de904368ad0adb8ef7ee8a98a080d67..ac7f579ebb5aa8bc8cd059b40d8dfab09de89dfb 100644 (file)
@@ -4,12 +4,14 @@
 
 use crate::ascii;
 use crate::convert::TryInto;
-use crate::error::Error;
 use crate::intrinsics;
 use crate::mem;
 use crate::ops::{Add, Mul, Sub};
 use crate::str::FromStr;
 
+#[cfg(not(no_fp_fmt_parse))]
+use crate::error::Error;
+
 // Used because the `?` operator is not allowed in a const context.
 macro_rules! try_opt {
     ($e:expr) => {
index 141cbc7669b0b42e13a8c8af115de2480f6dcb7c..6a339b338d990f87c410fd146eebdb29d59b9616 100644 (file)
@@ -1249,12 +1249,11 @@ impl $Ty {
                 /// # Examples
                 ///
                 /// ```
-                /// #![feature(nonzero_bits)]
                 #[doc = concat!("# use std::num::", stringify!($Ty), ";")]
                 ///
                 #[doc = concat!("assert_eq!(", stringify!($Ty), "::BITS, ", stringify!($Int), "::BITS);")]
                 /// ```
-                #[unstable(feature = "nonzero_bits", issue = "94881")]
+                #[stable(feature = "nonzero_bits", since = "CURRENT_RUSTC_VERSION")]
                 pub const BITS: u32 = <$Int>::BITS;
             }
         )+
index a5e5b13b33674ca1eaad2375281e9a74dfe5e048..eb2a92f4644d11e8bc903cceb47ac527afbde4eb 100644 (file)
 //! should have some resemblance to multiplication (and share expected
 //! properties like associativity).
 //!
-//! Note that the `&&` and `||` operators short-circuit, i.e., they only
-//! evaluate their second operand if it contributes to the result. Since this
-//! behavior is not enforceable by traits, `&&` and `||` are not supported as
-//! overloadable operators.
+//! Note that the `&&` and `||` operators are currently not supported for
+//! overloading. Due to their short circuiting nature, they require a different
+//! design from traits for other operators like [`BitAnd`]. Designs for them are
+//! under discussion.
 //!
 //! Many of the operators take their operands by value. In non-generic
 //! contexts involving built-in types, this is usually not a problem.
index 4fd1eb234137fb56cbe1fa6d22343b0daacb3aff..a704a00faaafadbbdedb51a3d1cb457dcb3992ed 100644 (file)
 /// site as much as possible (so that `panic!()` has as low an impact
 /// on (e.g.) the inlining of other functions as possible), by moving
 /// the actual formatting into this shared place.
-#[cold]
 // If panic_immediate_abort, inline the abort call,
 // otherwise avoid inlining because of it is cold path.
-#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))]
+#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold)]
 #[cfg_attr(feature = "panic_immediate_abort", inline)]
 #[track_caller]
 #[lang = "panic_fmt"] // needed for const-evaluated panics
@@ -67,8 +66,7 @@ pub const fn panic_fmt(fmt: fmt::Arguments<'_>) -> ! {
 
 /// Like panic_fmt, but without unwinding and track_caller to reduce the impact on codesize.
 /// Also just works on `str`, as a `fmt::Arguments` needs more space to be passed.
-#[cold]
-#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))]
+#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold)]
 #[cfg_attr(feature = "panic_immediate_abort", inline)]
 #[rustc_nounwind]
 pub fn panic_str_nounwind(msg: &'static str) -> ! {
@@ -96,10 +94,9 @@ pub fn panic_str_nounwind(msg: &'static str) -> ! {
 // above.
 
 /// The underlying implementation of libcore's `panic!` macro when no formatting is used.
-#[cold]
 // never inline unless panic_immediate_abort to avoid code
 // bloat at the call sites as much as possible
-#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))]
+#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold)]
 #[cfg_attr(feature = "panic_immediate_abort", inline)]
 #[track_caller]
 #[rustc_const_unstable(feature = "core_panic", issue = "none")]
@@ -138,8 +135,8 @@ pub const fn panic_display<T: fmt::Display>(x: &T) -> ! {
     panic_fmt(format_args!("{}", *x));
 }
 
-#[cold]
-#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))]
+#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold)]
+#[cfg_attr(feature = "panic_immediate_abort", inline)]
 #[track_caller]
 #[lang = "panic_bounds_check"] // needed by codegen for panic on OOB array/slice access
 fn panic_bounds_check(index: usize, len: usize) -> ! {
@@ -154,8 +151,8 @@ fn panic_bounds_check(index: usize, len: usize) -> ! {
 ///
 /// This function is called directly by the codegen backend, and must not have
 /// any extra arguments (including those synthesized by track_caller).
-#[cold]
-#[inline(never)]
+#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold)]
+#[cfg_attr(feature = "panic_immediate_abort", inline)]
 #[lang = "panic_no_unwind"] // needed by codegen for panic in nounwind function
 #[rustc_nounwind]
 fn panic_no_unwind() -> ! {
@@ -185,7 +182,8 @@ pub enum AssertKind {
 }
 
 /// Internal function for `assert_eq!` and `assert_ne!` macros
-#[cold]
+#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold)]
+#[cfg_attr(feature = "panic_immediate_abort", inline)]
 #[track_caller]
 #[doc(hidden)]
 pub fn assert_failed<T, U>(
@@ -202,7 +200,8 @@ pub fn assert_failed<T, U>(
 }
 
 /// Internal function for `assert_match!`
-#[cold]
+#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold)]
+#[cfg_attr(feature = "panic_immediate_abort", inline)]
 #[track_caller]
 #[doc(hidden)]
 pub fn assert_matches_failed<T: fmt::Debug + ?Sized>(
@@ -221,6 +220,8 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 }
 
 /// Non-generic version of the above functions, to avoid code bloat.
+#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold)]
+#[cfg_attr(feature = "panic_immediate_abort", inline)]
 #[track_caller]
 fn assert_failed_inner(
     kind: AssertKind,
index d3d255a802d7f626ec89be2d0d5f683ec5914254..2d67d742c689b21e0ca422bd52ca79e1ca7581a4 100644 (file)
     reason = "`cfg_eval` is a recently implemented feature"
 )]
 pub use crate::macros::builtin::cfg_eval;
+
+#[unstable(
+    feature = "type_ascription",
+    issue = "23416",
+    reason = "placeholder syntax for type ascription"
+)]
+#[cfg(not(bootstrap))]
+pub use crate::macros::builtin::type_ascribe;
index 76603e1018d19409951e6603d8c8e12fff6ed591..b6373beac5f76e651d2572ea12333b9c538abe79 100644 (file)
@@ -45,7 +45,7 @@ pub const fn is_null(self) -> bool {
     /// Casts to a pointer of another type.
     #[stable(feature = "ptr_cast", since = "1.38.0")]
     #[rustc_const_stable(feature = "const_ptr_cast", since = "1.38.0")]
-    #[inline]
+    #[inline(always)]
     pub const fn cast<U>(self) -> *const U {
         self as _
     }
@@ -95,6 +95,7 @@ pub const fn with_metadata_of<U>(self, meta: *const U) -> *const U
     /// refactored.
     #[stable(feature = "ptr_const_cast", since = "1.65.0")]
     #[rustc_const_stable(feature = "ptr_const_cast", since = "1.65.0")]
+    #[inline(always)]
     pub const fn cast_mut(self) -> *mut T {
         self as _
     }
@@ -126,6 +127,7 @@ pub const fn cast_mut(self) -> *mut T {
         note = "replaced by the `exposed_addr` method, or update your code \
             to follow the strict provenance rules using its APIs"
     )]
+    #[inline(always)]
     pub fn to_bits(self) -> usize
     where
         T: Sized,
@@ -155,6 +157,7 @@ pub fn to_bits(self) -> usize
             your code to follow the strict provenance rules using its APIs"
     )]
     #[allow(fuzzy_provenance_casts)] // this is an unstable and semi-deprecated cast function
+    #[inline(always)]
     pub fn from_bits(bits: usize) -> Self
     where
         T: Sized,
@@ -186,7 +189,7 @@ pub fn from_bits(bits: usize) -> Self
     /// might change in the future (including possibly weakening this so it becomes wholly
     /// equivalent to `self as usize`). See the [module documentation][crate::ptr] for details.
     #[must_use]
-    #[inline]
+    #[inline(always)]
     #[unstable(feature = "strict_provenance", issue = "95228")]
     pub fn addr(self) -> usize
     where
@@ -223,7 +226,7 @@ pub fn addr(self) -> usize
     ///
     /// [`from_exposed_addr`]: from_exposed_addr
     #[must_use]
-    #[inline]
+    #[inline(always)]
     #[unstable(feature = "strict_provenance", issue = "95228")]
     pub fn expose_addr(self) -> usize
     where
@@ -1005,7 +1008,7 @@ pub const fn guaranteed_ne(self, other: *const T) -> Option<bool>
     #[stable(feature = "pointer_methods", since = "1.26.0")]
     #[must_use = "returns a new pointer rather than modifying its argument"]
     #[rustc_const_stable(feature = "const_ptr_offset", since = "1.61.0")]
-    #[inline]
+    #[inline(always)]
     #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
     pub const unsafe fn sub(self, count: usize) -> Self
     where
@@ -1170,7 +1173,7 @@ pub const fn wrapping_byte_add(self, count: usize) -> Self {
     #[stable(feature = "pointer_methods", since = "1.26.0")]
     #[must_use = "returns a new pointer rather than modifying its argument"]
     #[rustc_const_stable(feature = "const_ptr_offset", since = "1.61.0")]
-    #[inline]
+    #[inline(always)]
     pub const fn wrapping_sub(self, count: usize) -> Self
     where
         T: Sized,
index 89b11637ecabefc0405209cfe16c11b6accc1912..48b2e88da28413d0e96c45f7ed9f9e974f046076 100644 (file)
@@ -613,7 +613,7 @@ pub const fn invalid_mut<T>(addr: usize) -> *mut T {
 /// This API and its claimed semantics are part of the Strict Provenance experiment, see the
 /// [module documentation][crate::ptr] for details.
 #[must_use]
-#[inline]
+#[inline(always)]
 #[unstable(feature = "strict_provenance", issue = "95228")]
 #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
 #[allow(fuzzy_provenance_casts)] // this *is* the strict provenance API one should use instead
@@ -651,7 +651,7 @@ pub fn from_exposed_addr<T>(addr: usize) -> *const T
 /// This API and its claimed semantics are part of the Strict Provenance experiment, see the
 /// [module documentation][crate::ptr] for details.
 #[must_use]
-#[inline]
+#[inline(always)]
 #[unstable(feature = "strict_provenance", issue = "95228")]
 #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
 #[allow(fuzzy_provenance_casts)] // this *is* the strict provenance API one should use instead
@@ -1769,7 +1769,7 @@ pub unsafe fn write_volatile<T>(dst: *mut T, src: T) {
 /// (which is what the `PartialEq for &T` implementation does).
 ///
 /// When comparing wide pointers, both the address and the metadata are tested for equality.
-/// However, note that comparing trait object pointers (`*const dyn Trait`) is unrealiable: pointers
+/// However, note that comparing trait object pointers (`*const dyn Trait`) is unreliable: pointers
 /// to values of the same underlying type can compare inequal (because vtables are duplicated in
 /// multiple codegen units), and pointers to values of *different* underlying type can compare equal
 /// (since identical vtables can be deduplicated within a codegen unit).
@@ -1801,7 +1801,7 @@ pub unsafe fn write_volatile<T>(dst: *mut T, src: T) {
 /// assert!(!std::ptr::eq(&a[0..2], &a[1..3]));
 /// ```
 #[stable(feature = "ptr_eq", since = "1.17.0")]
-#[inline]
+#[inline(always)]
 pub fn eq<T: ?Sized>(a: *const T, b: *const T) -> bool {
     a == b
 }
index b03cad18e4aedf81e89d19f8edd1329d0f5b4097..7a5d9a7059459986cda025f9caa317e0ae951d1b 100644 (file)
@@ -100,6 +100,7 @@ pub const fn with_metadata_of<U>(self, meta: *const U) -> *mut U
     /// [`cast_mut`]: #method.cast_mut
     #[stable(feature = "ptr_const_cast", since = "1.65.0")]
     #[rustc_const_stable(feature = "ptr_const_cast", since = "1.65.0")]
+    #[inline(always)]
     pub const fn cast_const(self) -> *const T {
         self as _
     }
@@ -132,6 +133,7 @@ pub const fn cast_const(self) -> *const T {
         note = "replaced by the `exposed_addr` method, or update your code \
             to follow the strict provenance rules using its APIs"
     )]
+    #[inline(always)]
     pub fn to_bits(self) -> usize
     where
         T: Sized,
@@ -161,6 +163,7 @@ pub fn to_bits(self) -> usize
             update your code to follow the strict provenance rules using its APIs"
     )]
     #[allow(fuzzy_provenance_casts)] // this is an unstable and semi-deprecated cast function
+    #[inline(always)]
     pub fn from_bits(bits: usize) -> Self
     where
         T: Sized,
@@ -192,7 +195,7 @@ pub fn from_bits(bits: usize) -> Self
     /// might change in the future (including possibly weakening this so it becomes wholly
     /// equivalent to `self as usize`). See the [module documentation][crate::ptr] for details.
     #[must_use]
-    #[inline]
+    #[inline(always)]
     #[unstable(feature = "strict_provenance", issue = "95228")]
     pub fn addr(self) -> usize
     where
@@ -229,7 +232,7 @@ pub fn addr(self) -> usize
     ///
     /// [`from_exposed_addr_mut`]: from_exposed_addr_mut
     #[must_use]
-    #[inline]
+    #[inline(always)]
     #[unstable(feature = "strict_provenance", issue = "95228")]
     pub fn expose_addr(self) -> usize
     where
@@ -1107,7 +1110,7 @@ pub const fn guaranteed_ne(self, other: *mut T) -> Option<bool>
     #[stable(feature = "pointer_methods", since = "1.26.0")]
     #[must_use = "returns a new pointer rather than modifying its argument"]
     #[rustc_const_stable(feature = "const_ptr_offset", since = "1.61.0")]
-    #[inline]
+    #[inline(always)]
     #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
     pub const unsafe fn sub(self, count: usize) -> Self
     where
@@ -1272,7 +1275,7 @@ pub const fn wrapping_byte_add(self, count: usize) -> Self {
     #[stable(feature = "pointer_methods", since = "1.26.0")]
     #[must_use = "returns a new pointer rather than modifying its argument"]
     #[rustc_const_stable(feature = "const_ptr_offset", since = "1.61.0")]
-    #[inline]
+    #[inline(always)]
     pub const fn wrapping_sub(self, count: usize) -> Self
     where
         T: Sized,
index c18264d13ebac78993f8cbc9ab9090ed521fe0be..c4348169c78c7e391e975f6d67cd9415264e8aa9 100644 (file)
@@ -330,7 +330,7 @@ pub fn map_addr(self, f: impl FnOnce(NonZeroUsize) -> NonZeroUsize) -> Self
     #[stable(feature = "nonnull", since = "1.25.0")]
     #[rustc_const_stable(feature = "const_nonnull_as_ptr", since = "1.32.0")]
     #[must_use]
-    #[inline]
+    #[inline(always)]
     pub const fn as_ptr(self) -> *mut T {
         self.pointer as *mut T
     }
@@ -378,7 +378,7 @@ pub const fn as_ptr(self) -> *mut T {
     #[stable(feature = "nonnull", since = "1.25.0")]
     #[rustc_const_unstable(feature = "const_ptr_as_ref", issue = "91822")]
     #[must_use]
-    #[inline]
+    #[inline(always)]
     pub const unsafe fn as_ref<'a>(&self) -> &'a T {
         // SAFETY: the caller must guarantee that `self` meets all the
         // requirements for a reference.
@@ -429,7 +429,7 @@ pub const fn as_ptr(self) -> *mut T {
     #[stable(feature = "nonnull", since = "1.25.0")]
     #[rustc_const_unstable(feature = "const_ptr_as_ref", issue = "91822")]
     #[must_use]
-    #[inline]
+    #[inline(always)]
     pub const unsafe fn as_mut<'a>(&mut self) -> &'a mut T {
         // SAFETY: the caller must guarantee that `self` meets all the
         // requirements for a mutable reference.
@@ -703,7 +703,7 @@ pub const fn as_mut_ptr(self) -> *mut T {
 #[stable(feature = "nonnull", since = "1.25.0")]
 #[rustc_const_unstable(feature = "const_clone", issue = "91805")]
 impl<T: ?Sized> const Clone for NonNull<T> {
-    #[inline]
+    #[inline(always)]
     fn clone(&self) -> Self {
         *self
     }
index 6d2f7330d5db55fd4b4a20dde265b8982351fb52..c295a0e06458d910a104c3242b711c1dc9e3081c 100644 (file)
@@ -31,9 +31,8 @@ fn index_mut(&mut self, index: I) -> &mut I::Output {
     }
 }
 
-#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))]
+#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold)]
 #[cfg_attr(feature = "panic_immediate_abort", inline)]
-#[cold]
 #[track_caller]
 #[rustc_const_unstable(feature = "const_slice_index", issue = "none")]
 const fn slice_start_index_len_fail(index: usize, len: usize) -> ! {
@@ -48,19 +47,20 @@ const fn slice_start_index_len_fail(index: usize, len: usize) -> ! {
 }
 
 // FIXME const-hack
+#[inline]
 #[track_caller]
 fn slice_start_index_len_fail_rt(index: usize, len: usize) -> ! {
     panic!("range start index {index} out of range for slice of length {len}");
 }
 
+#[inline]
 #[track_caller]
 const fn slice_start_index_len_fail_ct(_: usize, _: usize) -> ! {
     panic!("slice start index is out of range for slice");
 }
 
-#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))]
+#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold)]
 #[cfg_attr(feature = "panic_immediate_abort", inline)]
-#[cold]
 #[track_caller]
 #[rustc_const_unstable(feature = "const_slice_index", issue = "none")]
 const fn slice_end_index_len_fail(index: usize, len: usize) -> ! {
@@ -71,19 +71,20 @@ const fn slice_end_index_len_fail(index: usize, len: usize) -> ! {
 }
 
 // FIXME const-hack
+#[inline]
 #[track_caller]
 fn slice_end_index_len_fail_rt(index: usize, len: usize) -> ! {
     panic!("range end index {index} out of range for slice of length {len}");
 }
 
+#[inline]
 #[track_caller]
 const fn slice_end_index_len_fail_ct(_: usize, _: usize) -> ! {
     panic!("slice end index is out of range for slice");
 }
 
-#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))]
+#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold)]
 #[cfg_attr(feature = "panic_immediate_abort", inline)]
-#[cold]
 #[track_caller]
 #[rustc_const_unstable(feature = "const_slice_index", issue = "none")]
 const fn slice_index_order_fail(index: usize, end: usize) -> ! {
@@ -92,27 +93,27 @@ const fn slice_index_order_fail(index: usize, end: usize) -> ! {
 }
 
 // FIXME const-hack
+#[inline]
 #[track_caller]
 fn slice_index_order_fail_rt(index: usize, end: usize) -> ! {
     panic!("slice index starts at {index} but ends at {end}");
 }
 
+#[inline]
 #[track_caller]
 const fn slice_index_order_fail_ct(_: usize, _: usize) -> ! {
     panic!("slice index start is larger than end");
 }
 
-#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))]
+#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold)]
 #[cfg_attr(feature = "panic_immediate_abort", inline)]
-#[cold]
 #[track_caller]
 const fn slice_start_index_overflow_fail() -> ! {
     panic!("attempted to index slice from after maximum usize");
 }
 
-#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))]
+#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold)]
 #[cfg_attr(feature = "panic_immediate_abort", inline)]
-#[cold]
 #[track_caller]
 const fn slice_end_index_overflow_fail() -> ! {
     panic!("attempted to index slice up to maximum usize");
index 04486ed2d14e31a3c9c977ec9978e692b98b2a52..d9281a9252c08057e162462071a9eb59d1355d5a 100644 (file)
@@ -465,7 +465,7 @@ pub const fn get_mut<I>(&mut self, index: I) -> Option<&mut I::Output>
     /// [`as_mut_ptr`]: slice::as_mut_ptr
     #[stable(feature = "rust1", since = "1.0.0")]
     #[rustc_const_stable(feature = "const_slice_as_ptr", since = "1.32.0")]
-    #[inline]
+    #[inline(always)]
     #[must_use]
     pub const fn as_ptr(&self) -> *const T {
         self as *const [T] as *const T
@@ -495,7 +495,7 @@ pub const fn as_ptr(&self) -> *const T {
     #[stable(feature = "rust1", since = "1.0.0")]
     #[rustc_const_stable(feature = "const_ptr_offset", since = "1.61.0")]
     #[rustc_allow_const_fn_unstable(const_mut_refs)]
-    #[inline]
+    #[inline(always)]
     #[must_use]
     pub const fn as_mut_ptr(&mut self) -> *mut T {
         self as *mut [T] as *mut T
@@ -3468,10 +3468,11 @@ fn gcd(a: usize, b: usize) -> usize {
     /// maintained.
     ///
     /// This method splits the slice into three distinct slices: prefix, correctly aligned middle
-    /// slice of a new type, and the suffix slice. The method may make the middle slice the greatest
-    /// length possible for a given type and input slice, but only your algorithm's performance
-    /// should depend on that, not its correctness. It is permissible for all of the input data to
-    /// be returned as the prefix or suffix slice.
+    /// slice of a new type, and the suffix slice. How exactly the slice is split up is not
+    /// specified; the middle part may be smaller than necessary. However, if this fails to return a
+    /// maximal middle part, that is because code is running in a context where performance does not
+    /// matter, such as a sanitizer attempting to find alignment bugs. Regular code running
+    /// in a default (debug or release) execution *will* return a maximal middle part.
     ///
     /// This method has no purpose when either input element `T` or output element `U` are
     /// zero-sized and will return the original slice without splitting anything.
@@ -3529,10 +3530,11 @@ pub unsafe fn align_to<U>(&self) -> (&[T], &[U], &[T]) {
     /// types is maintained.
     ///
     /// This method splits the slice into three distinct slices: prefix, correctly aligned middle
-    /// slice of a new type, and the suffix slice. The method may make the middle slice the greatest
-    /// length possible for a given type and input slice, but only your algorithm's performance
-    /// should depend on that, not its correctness. It is permissible for all of the input data to
-    /// be returned as the prefix or suffix slice.
+    /// slice of a new type, and the suffix slice. How exactly the slice is split up is not
+    /// specified; the middle part may be smaller than necessary. However, if this fails to return a
+    /// maximal middle part, that is because code is running in a context where performance does not
+    /// matter, such as a sanitizer attempting to find alignment bugs. Regular code running
+    /// in a default (debug or release) execution *will* return a maximal middle part.
     ///
     /// This method has no purpose when either input element `T` or output element `U` are
     /// zero-sized and will return the original slice without splitting anything.
index c0167388713388d7f1e4adbd00c54962eb5a7958..45fd2caae52f4f27efe70ac4054c9660fc3bec99 100644 (file)
@@ -396,7 +396,7 @@ pub unsafe fn as_bytes_mut(&mut self) -> &mut [u8] {
     #[stable(feature = "rust1", since = "1.0.0")]
     #[rustc_const_stable(feature = "rustc_str_as_ptr", since = "1.32.0")]
     #[must_use]
-    #[inline]
+    #[inline(always)]
     pub const fn as_ptr(&self) -> *const u8 {
         self as *const str as *const u8
     }
@@ -411,7 +411,7 @@ pub const fn as_ptr(&self) -> *const u8 {
     /// modified in a way that it remains valid UTF-8.
     #[stable(feature = "str_as_mut_ptr", since = "1.36.0")]
     #[must_use]
-    #[inline]
+    #[inline(always)]
     pub fn as_mut_ptr(&mut self) -> *mut u8 {
         self as *mut str as *mut u8
     }
index d76d6f8b2a2d997a8324e75448025a7db7de3ebc..19da6d2fbecbc678960fcd282219f63cc5c2264a 100644 (file)
@@ -1894,7 +1894,7 @@ unsafe fn small_slice_eq(x: &[u8], y: &[u8]) -> bool {
     // Thus, derefencing both `px` and `py` in the loop below is safe.
     //
     // Moreover, we set `pxend` and `pyend` to be 4 bytes before the actual
-    // end of of `px` and `py`. Thus, the final dereference outside of the
+    // end of `px` and `py`. Thus, the final dereference outside of the
     // loop is guaranteed to be valid. (The final comparison will overlap with
     // the last comparison done in the loop for lengths that aren't multiples
     // of four.)
index 0cff972df3a5a8d4e961fe5fca309ab69a62b827..9ab9b0ba1c79739548fc891ba34d5d0f33bb82dc 100644 (file)
@@ -174,6 +174,7 @@ pub const fn new(
 /// Currently, `Context` only serves to provide access to a [`&Waker`](Waker)
 /// which can be used to wake the current task.
 #[stable(feature = "futures_api", since = "1.36.0")]
+#[cfg_attr(not(bootstrap), lang = "Context")]
 pub struct Context<'a> {
     waker: &'a Waker,
     // Ensure we future-proof against variance changes by forcing
index c10bfde4ddf79c946d4b9623356cf2b639f5d3fd..29b5a468bf4c502d582e0d369067b8c50af5eaea 100644 (file)
@@ -15,8 +15,8 @@ cfg-if = { version = "1.0", features = ['rustc-dep-of-std'] }
 panic_unwind = { path = "../panic_unwind", optional = true }
 panic_abort = { path = "../panic_abort" }
 core = { path = "../core" }
-libc = { version = "0.2.135", default-features = false, features = ['rustc-dep-of-std'] }
-compiler_builtins = { version = "0.1.82" }
+libc = { version = "0.2.138", default-features = false, features = ['rustc-dep-of-std'] }
+compiler_builtins = { version = "0.1.85" }
 profiler_builtins = { path = "../profiler_builtins", optional = true }
 unwind = { path = "../unwind" }
 hashbrown = { version = "0.12", default-features = false, features = ['rustc-dep-of-std'] }
index 6eb7cbea6269d7c92531fe00f1cb6a7edccb7f26..183f9ab3b08f632a2a945bd905be038571a125a9 100644 (file)
@@ -570,6 +570,13 @@ fn description(&self) -> &str {
 ///
 /// [msdn]: https://docs.microsoft.com/en-us/windows/win32/api/userenv/nf-userenv-getuserprofiledirectorya
 ///
+/// # Deprecation
+///
+/// This function is deprecated because the behaviour on Windows is not correct.
+/// The 'HOME' environment variable is not standard on Windows, and may not produce
+/// desired results; for instance, under Cygwin or Mingw it will return `/home/you`
+/// when it should return `C:\Users\you`.
+///
 /// # Examples
 ///
 /// ```
@@ -582,7 +589,7 @@ fn description(&self) -> &str {
 /// ```
 #[deprecated(
     since = "1.29.0",
-    note = "This function's behavior is unexpected and probably not what you want. \
+    note = "This function's behavior may be unexpected on Windows. \
             Consider using a crate from crates.io instead."
 )]
 #[must_use]
index 188ff00e1f8dda454aecd1e3ef4874a5259ddf7b..f357d505fe89ce2adcd50f2fdb08615651bc7fae 100644 (file)
@@ -401,7 +401,7 @@ pub fn create<P: AsRef<Path>>(path: P) -> io::Result<File> {
     ///     Ok(())
     /// }
     /// ```
-    #[unstable(feature = "file_create_new", issue = "none")]
+    #[unstable(feature = "file_create_new", issue = "105135")]
     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())
     }
@@ -510,8 +510,9 @@ pub fn sync_data(&self) -> io::Result<()> {
     /// # Errors
     ///
     /// This function will return an error if the file is not opened for writing.
-    /// Also, std::io::ErrorKind::InvalidInput will be returned if the desired
-    /// length would cause an overflow due to the implementation specifics.
+    /// Also, [`std::io::ErrorKind::InvalidInput`](crate::io::ErrorKind::InvalidInput)
+    /// will be returned if the desired length would cause an overflow due to
+    /// the implementation specifics.
     ///
     /// # Examples
     ///
index b8959316de170e568de3fc7a366ed478158855dc..4748ac9d97ef8fda19d11f2d2f48e403ef466fae 100644 (file)
@@ -1551,3 +1551,19 @@ fn hiberfil_sys() {
     fs::metadata(hiberfil).unwrap();
     assert_eq!(true, hiberfil.exists());
 }
+
+/// Test that two different ways of obtaining the FileType give the same result.
+/// Cf. https://github.com/rust-lang/rust/issues/104900
+#[test]
+fn test_eq_direntry_metadata() {
+    let tmpdir = tmpdir();
+    let file_path = tmpdir.join("file");
+    File::create(file_path).unwrap();
+    for e in fs::read_dir(tmpdir.path()).unwrap() {
+        let e = e.unwrap();
+        let p = e.path();
+        let ft1 = e.file_type().unwrap();
+        let ft2 = p.metadata().unwrap().file_type();
+        assert_eq!(ft1, ft2);
+    }
+}
index d4976a469cc15d4acbcec47ea13108c97cbb00ea..1039835bbbdfe5430d9f5175ed28b7b4d11ef883 100644 (file)
@@ -594,8 +594,8 @@ fn get(&mut self) -> &(dyn Any + Send) {
 // lang item for CTFE panic support
 // never inline unless panic_immediate_abort to avoid code
 // bloat at the call sites as much as possible
-#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))]
-#[cold]
+#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold)]
+#[cfg_attr(feature = "panic_immediate_abort", inline)]
 #[track_caller]
 #[rustc_do_not_const_check] // hooked by const-eval
 pub const fn begin_panic<M: Any + Send>(msg: M) -> ! {
index d5ac16e6b94e27a6f80b83c475e4500f4128e615..a5a798078eb984ea4772c5e4f6a72ba7ecbd1f0d 100644 (file)
 )]
 pub use core::prelude::v1::cfg_eval;
 
+// Do not `doc(no_inline)` either.
+#[unstable(
+    feature = "type_ascription",
+    issue = "23416",
+    reason = "placeholder syntax for type ascription"
+)]
+#[cfg(not(bootstrap))]
+pub use core::prelude::v1::type_ascribe;
+
 // The file so far is equivalent to src/libcore/prelude/v1.rs,
 // and below to src/liballoc/prelude.rs.
 // Those files are duplicated rather than using glob imports
index 4db7b4990b97d7465b01952334d082e2a56bf6b6..f71edc6c525a2aeb61abe424c19588741786326b 100644 (file)
@@ -225,7 +225,7 @@ fn start_recv(&self, token: &mut Token) -> bool {
             let slot = unsafe { self.buffer.get_unchecked(index) };
             let stamp = slot.stamp.load(Ordering::Acquire);
 
-            // If the the stamp is ahead of the head by 1, we may attempt to pop.
+            // If the stamp is ahead of the head by 1, we may attempt to pop.
             if head + 1 == stamp {
                 let new = if index + 1 < self.cap {
                     // Same lap, incremented index.
index 27fba761ada108c191ec9cbe9ddcea4c3b33ee95..adb488d4378f0391140e6eadf604603720f8776f 100644 (file)
@@ -629,9 +629,7 @@ fn clone(&self) -> Sender<T> {
 
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<T> Drop for Sender<T> {
-    fn drop(&mut self) {
-        let _ = self.inner;
-    }
+    fn drop(&mut self) {}
 }
 
 #[stable(feature = "mpsc_debug", since = "1.8.0")]
@@ -751,9 +749,7 @@ fn clone(&self) -> SyncSender<T> {
 
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<T> Drop for SyncSender<T> {
-    fn drop(&mut self) {
-        let _ = self.inner;
-    }
+    fn drop(&mut self) {}
 }
 
 #[stable(feature = "mpsc_debug", since = "1.8.0")]
@@ -1094,9 +1090,7 @@ fn into_iter(self) -> IntoIter<T> {
 
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<T> Drop for Receiver<T> {
-    fn drop(&mut self) {
-        let _ = self.inner;
-    }
+    fn drop(&mut self) {}
 }
 
 #[stable(feature = "mpsc_debug", since = "1.8.0")]
index f70aa434e48348b3b5289a52cdbc632d2f625b2e..7a47cc6696a34908a0bea6f832dbf14e8b68087d 100644 (file)
@@ -71,7 +71,7 @@ pub unsafe fn wait(&self, mutex: &Mutex) {
             }
         }
 
-        unsafe { mutex.lock() };
+        mutex.lock();
     }
 
     pub unsafe fn wait_timeout(&self, mutex: &Mutex, dur: Duration) -> bool {
@@ -109,7 +109,7 @@ pub unsafe fn wait_timeout(&self, mutex: &Mutex, dur: Duration) -> bool {
         // we woke up because of `notify_*`.
         let success = self.waiters.with_locked(|waiters| unsafe { !waiters.remove(waiter) });
 
-        unsafe { mutex.lock() };
+        mutex.lock();
         success
     }
 }
index f2eed8e771c40ece6fd04b090ae918c3843f694b..1f6cc41947602be1a7f81d443972de6e26b78d69 100644 (file)
@@ -72,7 +72,7 @@ fn drop(&mut self) {
 impl<'a> MutexGuard<'a> {
     #[inline]
     pub(super) fn lock(x: &'a Mutex) -> Self {
-        unsafe { x.lock() };
+        x.lock();
         Self(x)
     }
 }
index d28f57f33be20566de33bd7a79389a85067105a6..c2b3668087225cdc884a28d3a15660974c16b98d 100644 (file)
     ffi::CStr,
     hint, io,
     mem::ManuallyDrop,
+    ptr::NonNull,
     sync::atomic::{AtomicUsize, Ordering},
     sys::thread_local_dtor::run_dtors,
     time::Duration,
 };
 
 pub struct Thread {
-    inner: ManuallyDrop<Box<ThreadInner>>,
+    p_inner: NonNull<ThreadInner>,
 
     /// The ID of the underlying task.
     task: abi::ID,
 }
 
+// Safety: There's nothing in `Thread` that ties it to the original creator. It
+//         can be dropped by any threads.
+unsafe impl Send for Thread {}
+// Safety: `Thread` provides no methods that take `&self`.
+unsafe impl Sync for Thread {}
+
 /// State data shared between a parent thread and child thread. It's dropped on
 /// a transition to one of the final states.
 struct ThreadInner {
@@ -90,8 +97,9 @@ pub unsafe fn new(stack: usize, p: Box<dyn FnOnce()>) -> io::Result<Thread> {
         });
 
         unsafe extern "C" fn trampoline(exinf: isize) {
+            let p_inner: *mut ThreadInner = crate::ptr::from_exposed_addr_mut(exinf as usize);
             // Safety: `ThreadInner` is alive at this point
-            let inner = unsafe { &*(exinf as *const ThreadInner) };
+            let inner = unsafe { &*p_inner };
 
             // Safety: Since `trampoline` is called only once for each
             //         `ThreadInner` and only `trampoline` touches `start`,
@@ -119,13 +127,13 @@ pub unsafe fn new(stack: usize, p: Box<dyn FnOnce()>) -> io::Result<Thread> {
                     // No one will ever join, so we'll ask the collector task to
                     // delete the task.
 
-                    // In this case, `inner`'s ownership has been moved to us,
-                    // And we are responsible for dropping it. The acquire
+                    // In this case, `*p_inner`'s ownership has been moved to
+                    // us, and we are responsible for dropping it. The acquire
                     // ordering is not necessary because the parent thread made
                     // no memory access needing synchronization since the call
                     // to `acre_tsk`.
                     // Safety: See above.
-                    let _ = unsafe { Box::from_raw(inner as *const _ as *mut ThreadInner) };
+                    let _ = unsafe { Box::from_raw(p_inner) };
 
                     // Safety: There are no pinned references to the stack
                     unsafe { terminate_and_delete_current_task() };
@@ -162,13 +170,14 @@ pub unsafe fn new(stack: usize, p: Box<dyn FnOnce()>) -> io::Result<Thread> {
             }
         }
 
-        let inner_ptr = (&*inner) as *const ThreadInner;
+        // Safety: `Box::into_raw` returns a non-null pointer
+        let p_inner = unsafe { NonNull::new_unchecked(Box::into_raw(inner)) };
 
         let new_task = ItronError::err_if_negative(unsafe {
             abi::acre_tsk(&abi::T_CTSK {
                 // Activate this task immediately
                 tskatr: abi::TA_ACT,
-                exinf: inner_ptr as abi::EXINF,
+                exinf: p_inner.as_ptr().expose_addr() as abi::EXINF,
                 // The entry point
                 task: Some(trampoline),
                 // Inherit the calling task's base priority
@@ -180,7 +189,7 @@ pub unsafe fn new(stack: usize, p: Box<dyn FnOnce()>) -> io::Result<Thread> {
         })
         .map_err(|e| e.as_io_error())?;
 
-        Ok(Self { inner: ManuallyDrop::new(inner), task: new_task })
+        Ok(Self { p_inner, task: new_task })
     }
 
     pub fn yield_now() {
@@ -197,8 +206,9 @@ pub fn sleep(dur: Duration) {
         }
     }
 
-    pub fn join(mut self) {
-        let inner = &*self.inner;
+    pub fn join(self) {
+        // Safety: `ThreadInner` is alive at this point
+        let inner = unsafe { self.p_inner.as_ref() };
         // Get the current task ID. Panicking here would cause a resource leak,
         // so just abort on failure.
         let current_task = task::current_task_id_aborting();
@@ -243,8 +253,8 @@ pub fn join(mut self) {
         unsafe { terminate_and_delete_task(self.task) };
 
         // In either case, we are responsible for dropping `inner`.
-        // Safety: The contents of `self.inner` will not be accessed hereafter
-        let _inner = unsafe { ManuallyDrop::take(&mut self.inner) };
+        // Safety: The contents of `*p_inner` will not be accessed hereafter
+        let _inner = unsafe { Box::from_raw(self.p_inner.as_ptr()) };
 
         // Skip the destructor (because it would attempt to detach the thread)
         crate::mem::forget(self);
@@ -253,13 +263,16 @@ pub fn join(mut self) {
 
 impl Drop for Thread {
     fn drop(&mut self) {
+        // Safety: `ThreadInner` is alive at this point
+        let inner = unsafe { self.p_inner.as_ref() };
+
         // Detach the thread.
-        match self.inner.lifecycle.swap(LIFECYCLE_DETACHED_OR_JOINED, Ordering::Acquire) {
+        match inner.lifecycle.swap(LIFECYCLE_DETACHED_OR_JOINED, Ordering::Acquire) {
             LIFECYCLE_INIT => {
                 // [INIT â†’ DETACHED]
                 // When the time comes, the child will figure out that no
                 // one will ever join it.
-                // The ownership of `self.inner` is moved to the child thread.
+                // The ownership of `*p_inner` is moved to the child thread.
                 // However, the release ordering is not necessary because we
                 // made no memory access needing synchronization since the call
                 // to `acre_tsk`.
@@ -278,10 +291,9 @@ fn drop(&mut self) {
                 //         delete by entering the `FINISHED` state.
                 unsafe { terminate_and_delete_task(self.task) };
 
-                // Wwe are responsible for dropping `inner`.
-                // Safety: The contents of `self.inner` will not be accessed
-                //         hereafter
-                unsafe { ManuallyDrop::drop(&mut self.inner) };
+                // Wwe are responsible for dropping `*p_inner`.
+                // Safety: The contents of `*p_inner` will not be accessed hereafter
+                let _ = unsafe { Box::from_raw(self.p_inner.as_ptr()) };
             }
             _ => unsafe { hint::unreachable_unchecked() },
         }
index 01e4ffe3dfc8a04394145b67726b934d780b58d8..63e070207cd707cca701b47e7db0ca5e05b6b4eb 100644 (file)
@@ -34,6 +34,7 @@
 pub mod stdio;
 pub mod thread;
 pub mod thread_local_key;
+pub mod thread_parker;
 pub mod time;
 
 mod condvar;
index d745a619614041dc7e9eb9335f4f3bb48ee97d50..579f758c6cc339fe10f5eb65192851c5e48bf15c 100644 (file)
@@ -65,39 +65,36 @@ pub(super) fn lock() -> MutexGuard<'static, Vec<Task>> {
 /// execution. The signal is sent once all TLS destructors have finished at
 /// which point no new thread locals should be created.
 pub mod wait_notify {
-    use super::super::waitqueue::{SpinMutex, WaitQueue, WaitVariable};
+    use super::super::thread_parker::Parker;
+    use crate::pin::Pin;
     use crate::sync::Arc;
 
-    pub struct Notifier(Arc<SpinMutex<WaitVariable<bool>>>);
+    pub struct Notifier(Arc<Parker>);
 
     impl Notifier {
         /// Notify the waiter. The waiter is either notified right away (if
         /// currently blocked in `Waiter::wait()`) or later when it calls the
         /// `Waiter::wait()` method.
         pub fn notify(self) {
-            let mut guard = self.0.lock();
-            *guard.lock_var_mut() = true;
-            let _ = WaitQueue::notify_one(guard);
+            Pin::new(&*self.0).unpark()
         }
     }
 
-    pub struct Waiter(Arc<SpinMutex<WaitVariable<bool>>>);
+    pub struct Waiter(Arc<Parker>);
 
     impl Waiter {
         /// Wait for a notification. If `Notifier::notify()` has already been
         /// called, this will return immediately, otherwise the current thread
         /// is blocked until notified.
         pub fn wait(self) {
-            let guard = self.0.lock();
-            if *guard.lock_var() {
-                return;
-            }
-            WaitQueue::wait(guard, || {});
+            // This is not actually `unsafe`, but it uses the `Parker` API,
+            // which needs `unsafe` on some platforms.
+            unsafe { Pin::new(&*self.0).park() }
         }
     }
 
     pub fn new() -> (Notifier, Waiter) {
-        let inner = Arc::new(SpinMutex::new(WaitVariable::new(false)));
+        let inner = Arc::new(Parker::new_internal());
         (Notifier(inner.clone()), Waiter(inner))
     }
 }
diff --git a/library/std/src/sys/sgx/thread_parker.rs b/library/std/src/sys/sgx/thread_parker.rs
new file mode 100644 (file)
index 0000000..1c55bcf
--- /dev/null
@@ -0,0 +1,107 @@
+//! Thread parking based on SGX events.
+
+use super::abi::{thread, usercalls};
+use crate::io::ErrorKind;
+use crate::pin::Pin;
+use crate::ptr::{self, NonNull};
+use crate::sync::atomic::AtomicPtr;
+use crate::sync::atomic::Ordering::{Acquire, Relaxed, Release};
+use crate::time::Duration;
+use fortanix_sgx_abi::{EV_UNPARK, WAIT_INDEFINITE};
+
+// The TCS structure must be page-aligned (this is checked by EENTER), so these cannot
+// be valid pointers
+const EMPTY: *mut u8 = ptr::invalid_mut(1);
+const NOTIFIED: *mut u8 = ptr::invalid_mut(2);
+
+pub struct Parker {
+    /// The park state. One of EMPTY, NOTIFIED or a TCS address.
+    /// A state change to NOTIFIED must be done with release ordering
+    /// and be observed with acquire ordering so that operations after
+    /// `thread::park` returns will not occur before the unpark message
+    /// was sent.
+    state: AtomicPtr<u8>,
+}
+
+impl Parker {
+    /// Construct the thread parker. The UNIX parker implementation
+    /// requires this to happen in-place.
+    pub unsafe fn new(parker: *mut Parker) {
+        unsafe { parker.write(Parker::new_internal()) }
+    }
+
+    pub(super) fn new_internal() -> Parker {
+        Parker { state: AtomicPtr::new(EMPTY) }
+    }
+
+    // This implementation doesn't require `unsafe` and `Pin`, but other implementations do.
+    pub unsafe fn park(self: Pin<&Self>) {
+        if self.state.load(Acquire) != NOTIFIED {
+            let mut prev = EMPTY;
+            loop {
+                // Guard against changing TCS addresses by always setting the state to
+                // the current value.
+                let tcs = thread::current().as_ptr();
+                if self.state.compare_exchange(prev, tcs, Relaxed, Acquire).is_ok() {
+                    let event = usercalls::wait(EV_UNPARK, WAIT_INDEFINITE).unwrap();
+                    assert!(event & EV_UNPARK == EV_UNPARK);
+                    prev = tcs;
+                } else {
+                    // The state was definitely changed by another thread at this point.
+                    // The only time this occurs is when the state is changed to NOTIFIED.
+                    // We observed this change with acquire ordering, so we can simply
+                    // change the state to EMPTY with a relaxed store.
+                    break;
+                }
+            }
+        }
+
+        // At this point, the token was definately read with acquire ordering,
+        // so this can be a relaxed store.
+        self.state.store(EMPTY, Relaxed);
+    }
+
+    // This implementation doesn't require `unsafe` and `Pin`, but other implementations do.
+    pub unsafe fn park_timeout(self: Pin<&Self>, dur: Duration) {
+        let timeout = u128::min(dur.as_nanos(), WAIT_INDEFINITE as u128 - 1) as u64;
+        let tcs = thread::current().as_ptr();
+
+        if self.state.load(Acquire) != NOTIFIED {
+            if self.state.compare_exchange(EMPTY, tcs, Relaxed, Acquire).is_ok() {
+                match usercalls::wait(EV_UNPARK, timeout) {
+                    Ok(event) => assert!(event & EV_UNPARK == EV_UNPARK),
+                    Err(e) => {
+                        assert!(matches!(e.kind(), ErrorKind::TimedOut | ErrorKind::WouldBlock))
+                    }
+                }
+
+                // Swap to provide acquire ordering even if the timeout occurred
+                // before the token was set. This situation can result in spurious
+                // wakeups on the next call to `park_timeout`, but it is better to let
+                // those be handled by the user than do some perhaps unnecessary, but
+                // always expensive guarding.
+                self.state.swap(EMPTY, Acquire);
+                return;
+            }
+        }
+
+        // The token was already read with `acquire` ordering, this can be a store.
+        self.state.store(EMPTY, Relaxed);
+    }
+
+    // This implementation doesn't require `Pin`, but other implementations do.
+    pub fn unpark(self: Pin<&Self>) {
+        let state = self.state.swap(NOTIFIED, Release);
+
+        if !matches!(state, EMPTY | NOTIFIED) {
+            // There is a thread waiting, wake it up.
+            let tcs = NonNull::new(state).unwrap();
+            // This will fail if the thread has already terminated or its TCS is destroyed
+            // by the time the signal is sent, but that is fine. If another thread receives
+            // the same TCS, it will receive this notification as a spurious wakeup, but
+            // all users of `wait` should and (internally) do guard against those where
+            // necessary.
+            let _ = usercalls::send(EV_UNPARK, Some(tcs));
+        }
+    }
+}
index 9eb17a10daa287175a8a3005fc96d274bf666741..a862bb7870264e72ece3f8ee5c6bfc2a9ef0992f 100644 (file)
@@ -75,3 +75,7 @@ pub fn as_mut_slice(&mut self) -> &mut [u8] {
         unsafe { slice::from_raw_parts_mut(self.vec.iov_base as *mut u8, self.vec.iov_len) }
     }
 }
+
+pub fn is_terminal<T>(_: &T) -> bool {
+    false
+}
index 4906c62689d4c27671398aafd86862e7832274bb..6135921f0b5a89a6694d7d151130255981423c73 100644 (file)
@@ -1,7 +1,6 @@
 use super::unsupported;
-use crate::convert::TryFrom;
 use crate::error::Error as StdError;
-use crate::ffi::{CStr, CString, OsStr, OsString};
+use crate::ffi::{CStr, OsStr, OsString};
 use crate::fmt;
 use crate::io;
 use crate::os::{
index 37a49f2d78acdb24179d078f4e84b32ed017a573..fb8d06c66820cf0b47a41a48cfdfd8064d3c7f5f 100644 (file)
@@ -332,11 +332,23 @@ pub struct FileTimes {
     modified: Option<SystemTime>,
 }
 
-#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
+#[derive(Copy, Clone, Eq, Debug)]
 pub struct FileType {
     mode: mode_t,
 }
 
+impl PartialEq for FileType {
+    fn eq(&self, other: &Self) -> bool {
+        self.masked() == other.masked()
+    }
+}
+
+impl core::hash::Hash for FileType {
+    fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
+        self.masked().hash(state);
+    }
+}
+
 #[derive(Debug)]
 pub struct DirBuilder {
     mode: mode_t,
@@ -548,7 +560,11 @@ pub fn is_symlink(&self) -> bool {
     }
 
     pub fn is(&self, mode: mode_t) -> bool {
-        self.mode & libc::S_IFMT == mode
+        self.masked() == mode
+    }
+
+    fn masked(&self) -> mode_t {
+        self.mode & libc::S_IFMT
     }
 }
 
index 1ddb09905db2cfa0f3002535eb8729c3400310b9..6be1abc2b080a0164d772b5f6eed32b7f2bc9b9d 100644 (file)
@@ -2,6 +2,7 @@
 use crate::ptr;
 use crate::sync::atomic::{AtomicPtr, Ordering::Relaxed};
 use crate::sys::locks::{pthread_mutex, Mutex};
+use crate::sys::time::TIMESPEC_MAX;
 use crate::sys_common::lazy_box::{LazyBox, LazyInit};
 use crate::time::Duration;
 
@@ -12,13 +13,6 @@ pub struct Condvar {
     mutex: AtomicPtr<libc::pthread_mutex_t>,
 }
 
-const TIMESPEC_MAX: libc::timespec =
-    libc::timespec { tv_sec: <libc::time_t>::MAX, tv_nsec: 1_000_000_000 - 1 };
-
-fn saturating_cast_to_time_t(value: u64) -> libc::time_t {
-    if value > <libc::time_t>::MAX as u64 { <libc::time_t>::MAX } else { value as libc::time_t }
-}
-
 #[inline]
 fn raw(c: &Condvar) -> *mut libc::pthread_cond_t {
     c.inner.0.get()
@@ -133,26 +127,15 @@ pub unsafe fn wait(&self, mutex: &Mutex) {
         target_os = "horizon"
     )))]
     pub unsafe fn wait_timeout(&self, mutex: &Mutex, dur: Duration) -> bool {
-        use crate::mem;
+        use crate::sys::time::Timespec;
 
         let mutex = pthread_mutex::raw(mutex);
         self.verify(mutex);
 
-        let mut now: libc::timespec = mem::zeroed();
-        let r = libc::clock_gettime(libc::CLOCK_MONOTONIC, &mut now);
-        assert_eq!(r, 0);
-
-        // Nanosecond calculations can't overflow because both values are below 1e9.
-        let nsec = dur.subsec_nanos() + now.tv_nsec as u32;
-
-        let sec = saturating_cast_to_time_t(dur.as_secs())
-            .checked_add((nsec / 1_000_000_000) as libc::time_t)
-            .and_then(|s| s.checked_add(now.tv_sec));
-        let nsec = nsec % 1_000_000_000;
-
-        let timeout =
-            sec.map(|s| libc::timespec { tv_sec: s, tv_nsec: nsec as _ }).unwrap_or(TIMESPEC_MAX);
-
+        let timeout = Timespec::now(libc::CLOCK_MONOTONIC)
+            .checked_add_duration(&dur)
+            .and_then(|t| t.to_timespec())
+            .unwrap_or(TIMESPEC_MAX);
         let r = libc::pthread_cond_timedwait(raw(self), mutex, &timeout);
         assert!(r == libc::ETIMEDOUT || r == 0);
         r == 0
@@ -169,57 +152,41 @@ pub unsafe fn wait_timeout(&self, mutex: &Mutex, dur: Duration) -> bool {
         target_os = "espidf",
         target_os = "horizon"
     ))]
-    pub unsafe fn wait_timeout(&self, mutex: &Mutex, mut dur: Duration) -> bool {
+    pub unsafe fn wait_timeout(&self, mutex: &Mutex, dur: Duration) -> bool {
+        use crate::sys::time::SystemTime;
         use crate::time::Instant;
 
         let mutex = pthread_mutex::raw(mutex);
         self.verify(mutex);
 
-        // 1000 years
-        let max_dur = Duration::from_secs(1000 * 365 * 86400);
-
-        if dur > max_dur {
-            // OSX implementation of `pthread_cond_timedwait` is buggy
-            // with super long durations. When duration is greater than
-            // 0x100_0000_0000_0000 seconds, `pthread_cond_timedwait`
-            // in macOS Sierra return error 316.
-            //
-            // This program demonstrates the issue:
-            // https://gist.github.com/stepancheg/198db4623a20aad2ad7cddb8fda4a63c
-            //
-            // To work around this issue, and possible bugs of other OSes, timeout
-            // is clamped to 1000 years, which is allowable per the API of `wait_timeout`
-            // because of spurious wakeups.
-
-            dur = max_dur;
-        }
-
-        // First, figure out what time it currently is, in both system and
-        // stable time.  pthread_cond_timedwait uses system time, but we want to
-        // report timeout based on stable time.
-        let mut sys_now = libc::timeval { tv_sec: 0, tv_usec: 0 };
-        let stable_now = Instant::now();
-        let r = libc::gettimeofday(&mut sys_now, ptr::null_mut());
-        assert_eq!(r, 0, "unexpected error: {:?}", crate::io::Error::last_os_error());
-
-        let nsec = dur.subsec_nanos() as libc::c_long + (sys_now.tv_usec * 1000) as libc::c_long;
-        let extra = (nsec / 1_000_000_000) as libc::time_t;
-        let nsec = nsec % 1_000_000_000;
-        let seconds = saturating_cast_to_time_t(dur.as_secs());
-
-        let timeout = sys_now
-            .tv_sec
-            .checked_add(extra)
-            .and_then(|s| s.checked_add(seconds))
-            .map(|s| libc::timespec { tv_sec: s, tv_nsec: nsec })
+        // OSX implementation of `pthread_cond_timedwait` is buggy
+        // with super long durations. When duration is greater than
+        // 0x100_0000_0000_0000 seconds, `pthread_cond_timedwait`
+        // in macOS Sierra returns error 316.
+        //
+        // This program demonstrates the issue:
+        // https://gist.github.com/stepancheg/198db4623a20aad2ad7cddb8fda4a63c
+        //
+        // To work around this issue, and possible bugs of other OSes, timeout
+        // is clamped to 1000 years, which is allowable per the API of `wait_timeout`
+        // because of spurious wakeups.
+        let dur = Duration::min(dur, Duration::from_secs(1000 * 365 * 86400));
+
+        // pthread_cond_timedwait uses system time, but we want to report timeout
+        // based on stable time.
+        let now = Instant::now();
+
+        let timeout = SystemTime::now()
+            .t
+            .checked_add_duration(&dur)
+            .and_then(|t| t.to_timespec())
             .unwrap_or(TIMESPEC_MAX);
 
-        // And wait!
         let r = libc::pthread_cond_timedwait(raw(self), mutex, &timeout);
         debug_assert!(r == libc::ETIMEDOUT || r == 0);
 
         // ETIMEDOUT is not a totally reliable method of determining timeout due
         // to clock shifts, so do the check ourselves
-        stable_now.elapsed() < dur
+        now.elapsed() < dur
     }
 }
index c1d30dd9d521b318ed83cdf225df4ee918da1fcc..6ecf5bdcf86d2bf792695eb1720f3c10c403eadf 100644 (file)
@@ -136,7 +136,7 @@ pub fn set_name(name: &CStr) {
 
         unsafe {
             // Available since glibc 2.12, musl 1.1.16, and uClibc 1.0.20.
-            let name = truncate_cstr(name, TASK_COMM_LEN);
+            let name = truncate_cstr::<{ TASK_COMM_LEN }>(name);
             let res = libc::pthread_setname_np(libc::pthread_self(), name.as_ptr());
             // We have no good way of propagating errors here, but in debug-builds let's check that this actually worked.
             debug_assert_eq!(res, 0);
@@ -153,7 +153,7 @@ pub fn set_name(name: &CStr) {
     #[cfg(any(target_os = "macos", target_os = "ios", target_os = "watchos"))]
     pub fn set_name(name: &CStr) {
         unsafe {
-            let name = truncate_cstr(name, libc::MAXTHREADNAMESIZE);
+            let name = truncate_cstr::<{ libc::MAXTHREADNAMESIZE }>(name);
             let res = libc::pthread_setname_np(name.as_ptr());
             // We have no good way of propagating errors here, but in debug-builds let's check that this actually worked.
             debug_assert_eq!(res, 0);
@@ -285,17 +285,12 @@ fn drop(&mut self) {
 }
 
 #[cfg(any(target_os = "linux", target_os = "macos", target_os = "ios", target_os = "watchos"))]
-fn truncate_cstr(cstr: &CStr, max_with_nul: usize) -> crate::borrow::Cow<'_, CStr> {
-    use crate::{borrow::Cow, ffi::CString};
-
-    if cstr.to_bytes_with_nul().len() > max_with_nul {
-        let bytes = cstr.to_bytes()[..max_with_nul - 1].to_vec();
-        // SAFETY: the non-nul bytes came straight from a CStr.
-        // (CString will add the terminating nul.)
-        Cow::Owned(unsafe { CString::from_vec_unchecked(bytes) })
-    } else {
-        Cow::Borrowed(cstr)
+fn truncate_cstr<const MAX_WITH_NUL: usize>(cstr: &CStr) -> [libc::c_char; MAX_WITH_NUL] {
+    let mut result = [0; MAX_WITH_NUL];
+    for (src, dst) in cstr.to_bytes().iter().zip(&mut result[..MAX_WITH_NUL - 1]) {
+        *dst = *src as libc::c_char;
     }
+    result
 }
 
 pub fn available_parallelism() -> io::Result<NonZeroUsize> {
index 3dfc0026ed1a43a219c51c870c5d402944913789..c400c7715676f7856d47e3be8ed83e0c839cd340 100644 (file)
@@ -6,6 +6,7 @@
 use crate::ptr::addr_of_mut;
 use crate::sync::atomic::AtomicUsize;
 use crate::sync::atomic::Ordering::SeqCst;
+use crate::sys::time::TIMESPEC_MAX;
 use crate::time::Duration;
 
 const EMPTY: usize = 0;
@@ -32,9 +33,6 @@ unsafe fn wait(cond: *mut libc::pthread_cond_t, lock: *mut libc::pthread_mutex_t
     debug_assert_eq!(r, 0);
 }
 
-const TIMESPEC_MAX: libc::timespec =
-    libc::timespec { tv_sec: <libc::time_t>::MAX, tv_nsec: 1_000_000_000 - 1 };
-
 unsafe fn wait_timeout(
     cond: *mut libc::pthread_cond_t,
     lock: *mut libc::pthread_mutex_t,
index d5abd9b581c65b67adf203f4e8a5c345e5897de8..2daad981b73e9a94af6e3b3f779b029d4026076e 100644 (file)
@@ -5,6 +5,9 @@
 
 const NSEC_PER_SEC: u64 = 1_000_000_000;
 pub const UNIX_EPOCH: SystemTime = SystemTime { t: Timespec::zero() };
+#[allow(dead_code)] // Used for pthread condvar timeouts
+pub const TIMESPEC_MAX: libc::timespec =
+    libc::timespec { tv_sec: <libc::time_t>::MAX, tv_nsec: 1_000_000_000 - 1 };
 
 #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
 #[repr(transparent)]
index e4ff21b25bd9ce47aea69b7fd0f2eb696c873306..f5a4ce929b2a9219311c6c6d1298fad26c695b0c 100644 (file)
 use crate::sync::atomic::{self, AtomicPtr, Ordering};
 
 // We can use true weak linkage on ELF targets.
-#[cfg(not(any(target_os = "macos", target_os = "ios")))]
+#[cfg(all(not(any(target_os = "macos", target_os = "ios")), not(bootstrap)))]
+pub(crate) macro weak {
+    (fn $name:ident($($t:ty),*) -> $ret:ty) => (
+        let ref $name: ExternWeak<unsafe extern "C" fn($($t),*) -> $ret> = {
+            extern "C" {
+                #[linkage = "extern_weak"]
+                static $name: Option<unsafe extern "C" fn($($t),*) -> $ret>;
+            }
+            #[allow(unused_unsafe)]
+            ExternWeak::new(unsafe { $name })
+        };
+    )
+}
+
+#[cfg(all(not(any(target_os = "macos", target_os = "ios")), bootstrap))]
 pub(crate) macro weak {
     (fn $name:ident($($t:ty),*) -> $ret:ty) => (
         let ref $name: ExternWeak<unsafe extern "C" fn($($t),*) -> $ret> = {
 #[cfg(any(target_os = "macos", target_os = "ios"))]
 pub(crate) use self::dlsym as weak;
 
+#[cfg(not(bootstrap))]
+pub(crate) struct ExternWeak<F: Copy> {
+    weak_ptr: Option<F>,
+}
+
+#[cfg(not(bootstrap))]
+impl<F: Copy> ExternWeak<F> {
+    #[inline]
+    pub(crate) fn new(weak_ptr: Option<F>) -> Self {
+        ExternWeak { weak_ptr }
+    }
+
+    #[inline]
+    pub(crate) fn get(&self) -> Option<F> {
+        self.weak_ptr
+    }
+}
+
+#[cfg(bootstrap)]
 pub(crate) struct ExternWeak<F> {
     weak_ptr: *const libc::c_void,
     _marker: PhantomData<F>,
 }
 
+#[cfg(bootstrap)]
 impl<F> ExternWeak<F> {
     #[inline]
     pub(crate) fn new(weak_ptr: *const libc::c_void) -> Self {
@@ -59,6 +93,7 @@ pub(crate) fn new(weak_ptr: *const libc::c_void) -> Self {
     }
 }
 
+#[cfg(bootstrap)]
 impl<F> ExternWeak<F> {
     #[inline]
     pub(crate) fn get(&self) -> Option<F> {
index 9cbb4ef19e9b7a80dff8732c8e318dc2051b1c72..31e9b34fb9efdf1739cebdd4b100977fb5269af8 100644 (file)
@@ -252,10 +252,6 @@ pub fn spawn(
     ) -> io::Result<(Process, StdioPipes)> {
         let maybe_env = self.env.capture_if_changed();
 
-        let mut si = zeroed_startupinfo();
-        si.cb = mem::size_of::<c::STARTUPINFO>() as c::DWORD;
-        si.dwFlags = c::STARTF_USESTDHANDLES;
-
         let child_paths = if let Some(env) = maybe_env.as_ref() {
             env.get(&EnvKey::new("PATH")).map(|s| s.as_os_str())
         } else {
@@ -314,9 +310,21 @@ pub fn spawn(
         let stdin = stdin.to_handle(c::STD_INPUT_HANDLE, &mut pipes.stdin)?;
         let stdout = stdout.to_handle(c::STD_OUTPUT_HANDLE, &mut pipes.stdout)?;
         let stderr = stderr.to_handle(c::STD_ERROR_HANDLE, &mut pipes.stderr)?;
-        si.hStdInput = stdin.as_raw_handle();
-        si.hStdOutput = stdout.as_raw_handle();
-        si.hStdError = stderr.as_raw_handle();
+
+        let mut si = zeroed_startupinfo();
+        si.cb = mem::size_of::<c::STARTUPINFO>() as c::DWORD;
+
+        // If at least one of stdin, stdout or stderr are set (i.e. are non null)
+        // then set the `hStd` fields in `STARTUPINFO`.
+        // Otherwise skip this and allow the OS to apply its default behaviour.
+        // This provides more consistent behaviour between Win7 and Win8+.
+        let is_set = |stdio: &Handle| !stdio.as_raw_handle().is_null();
+        if is_set(&stderr) || is_set(&stdout) || is_set(&stdin) {
+            si.dwFlags |= c::STARTF_USESTDHANDLES;
+            si.hStdInput = stdin.as_raw_handle();
+            si.hStdOutput = stdout.as_raw_handle();
+            si.hStdError = stderr.as_raw_handle();
+        }
 
         unsafe {
             cvt(c::CreateProcessW(
@@ -513,9 +521,6 @@ fn program_exists(path: &Path) -> Option<Vec<u16>> {
 impl Stdio {
     fn to_handle(&self, stdio_id: c::DWORD, pipe: &mut Option<AnonPipe>) -> io::Result<Handle> {
         match *self {
-            // If no stdio handle is available, then inherit means that it
-            // should still be unavailable so propagate the
-            // INVALID_HANDLE_VALUE.
             Stdio::Inherit => match stdio::get_handle(stdio_id) {
                 Ok(io) => unsafe {
                     let io = Handle::from_raw_handle(io);
@@ -523,7 +528,8 @@ fn to_handle(&self, stdio_id: c::DWORD, pipe: &mut Option<AnonPipe>) -> io::Resu
                     io.into_raw_handle();
                     ret
                 },
-                Err(..) => unsafe { Ok(Handle::from_raw_handle(c::INVALID_HANDLE_VALUE)) },
+                // If no stdio handle is available, then propagate the null value.
+                Err(..) => unsafe { Ok(Handle::from_raw_handle(ptr::null_mut())) },
             },
 
             Stdio::MakePipe => {
@@ -730,9 +736,9 @@ fn zeroed_startupinfo() -> c::STARTUPINFO {
         wShowWindow: 0,
         cbReserved2: 0,
         lpReserved2: ptr::null_mut(),
-        hStdInput: c::INVALID_HANDLE_VALUE,
-        hStdOutput: c::INVALID_HANDLE_VALUE,
-        hStdError: c::INVALID_HANDLE_VALUE,
+        hStdInput: ptr::null_mut(),
+        hStdOutput: ptr::null_mut(),
+        hStdError: ptr::null_mut(),
     }
 }
 
index f86a9a555d322e02c08c885aadcd4af194795921..08a2bdd82298b9f622e5589ff2550d20ccd0658a 100644 (file)
@@ -16,6 +16,8 @@
         pub use wait_flag::Parker;
     } else if #[cfg(any(windows, target_family = "unix"))] {
         pub use crate::sys::thread_parker::Parker;
+    } else if #[cfg(all(target_vendor = "fortanix", target_env = "sgx"))] {
+        pub use crate::sys::thread_parker::Parker;
     } else {
         mod generic;
         pub use generic::Parker;
index e6dbf35bd0286f7abdc2a1715ab2c4a3d1f0b1b5..ada69aa8269f6cb1ea4779486c5e07d90e8c30a6 100644 (file)
@@ -46,7 +46,7 @@ pub(super) fn increment_num_running_threads(&self) {
         // We check for 'overflow' with usize::MAX / 2, to make sure there's no
         // chance it overflows to 0, which would result in unsoundness.
         if self.num_running_threads.fetch_add(1, Ordering::Relaxed) > usize::MAX / 2 {
-            // This can only reasonably happen by mem::forget()'ing many many ScopedJoinHandles.
+            // This can only reasonably happen by mem::forget()'ing a lot of ScopedJoinHandles.
             self.decrement_num_running_threads(false);
             panic!("too many running threads in thread scope");
         }
index 8be32183fe780faa066052a08d84c14036850642..524658bce139d73794a18ca88237241a6aec1dce 100644 (file)
@@ -26,6 +26,10 @@ pub struct TestOpts {
     pub test_threads: Option<usize>,
     pub skip: Vec<String>,
     pub time_options: Option<TestTimeOptions>,
+    /// Stop at first failing test.
+    /// May run a few more tests due to threading, but will
+    /// abort as soon as possible.
+    pub fail_fast: bool,
     pub options: Options,
 }
 
@@ -296,6 +300,7 @@ fn parse_opts_impl(matches: getopts::Matches) -> OptRes {
         skip,
         time_options,
         options,
+        fail_fast: false,
     };
 
     Ok(test_opts)
index 8cb88016b23ade5b5fb6bdfdf9dce3f128440576..a3c39f71f08b88ef38fd3e7673a78d062a78f630 100644 (file)
@@ -293,7 +293,7 @@ pub fn run_tests_console(opts: &TestOpts, tests: Vec<TestDescAndFn>) -> io::Resu
     run_tests(opts, tests, |x| on_test_event(&x, &mut st, &mut *out))?;
     st.exec_time = start_time.map(|t| TestSuiteExecTime(t.elapsed()));
 
-    assert!(st.current_test_count() == st.total);
+    assert!(opts.fail_fast || st.current_test_count() == st.total);
 
     out.write_run_finish(&st)
 }
index 27320e8dbc5ad42738fecaeea8131444bbc961f0..256c9e8d141e0baa57684ec5ebdb9c74cb5fc7c0 100644 (file)
@@ -384,8 +384,17 @@ fn calc_timeout(timeout_queue: &VecDeque<TimeoutEntry>) -> Option<Duration> {
             let mut completed_test = rx.recv().unwrap();
             RunningTest { join_handle }.join(&mut completed_test);
 
+            let fail_fast = match completed_test.result {
+                TrIgnored | TrOk | TrBench(_) => false,
+                TrFailed | TrFailedMsg(_) | TrTimedFail => opts.fail_fast,
+            };
+
             let event = TestEvent::TeResult(completed_test);
             notify_about_test_event(event)?;
+
+            if fail_fast {
+                return Ok(());
+            }
         }
     } else {
         while pending > 0 || !remaining.is_empty() {
@@ -431,9 +440,20 @@ fn calc_timeout(timeout_queue: &VecDeque<TimeoutEntry>) -> Option<Duration> {
             let running_test = running_tests.remove(&completed_test.id).unwrap();
             running_test.join(&mut completed_test);
 
+            let fail_fast = match completed_test.result {
+                TrIgnored | TrOk | TrBench(_) => false,
+                TrFailed | TrFailedMsg(_) | TrTimedFail => opts.fail_fast,
+            };
+
             let event = TestEvent::TeResult(completed_test);
             notify_about_test_event(event)?;
             pending -= 1;
+
+            if fail_fast {
+                // Prevent remaining test threads from panicking
+                std::mem::forget(rx);
+                return Ok(());
+            }
         }
     }
 
index 7b2e6707f9d11243b112b3b7ef5f2a3c71e37fdc..3a0260f86cf5d081f08a4b6122a0f40c3ed77b38 100644 (file)
@@ -51,6 +51,7 @@ fn new() -> TestOpts {
             skip: vec![],
             time_options: None,
             options: Options::new(),
+            fail_fast: false,
         }
     }
 }
index fe8a028dfd3ade5cab2a1c5e0510fadcba88fae6..efe8ae3169fc2f9e4ca678f809a3d7aaf095bec4 100644 (file)
@@ -11,15 +11,6 @@ dependencies = [
  "memchr",
 ]
 
-[[package]]
-name = "ansi_term"
-version = "0.12.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2"
-dependencies = [
- "winapi",
-]
-
 [[package]]
 name = "autocfg"
 version = "1.1.0"
@@ -108,18 +99,18 @@ checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc"
 
 [[package]]
 name = "cpufeatures"
-version = "0.2.2"
+version = "0.2.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "59a6001667ab124aebae2a495118e11d30984c3a653e99d86d58971708cf5e4b"
+checksum = "28d997bd5e24a5928dd43e46dc529867e207907fe0b239c3477d924f7f2ca320"
 dependencies = [
  "libc",
 ]
 
 [[package]]
 name = "crossbeam-channel"
-version = "0.5.4"
+version = "0.5.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5aaa7bd5fb665c6864b5f963dd9097905c54125909c7aa94c9e18507cdbe6c53"
+checksum = "c2dd04ddaf88237dc3b8d8f9a3c1004b506b54b3313403944054d23c0870c521"
 dependencies = [
  "cfg-if",
  "crossbeam-utils",
@@ -127,9 +118,9 @@ dependencies = [
 
 [[package]]
 name = "crossbeam-deque"
-version = "0.8.1"
+version = "0.8.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6455c0ca19f0d2fbf751b908d5c55c1f5cbc65e03c4225427254b46890bdde1e"
+checksum = "715e8152b692bba2d374b53d4875445368fdf21a94751410af607a5ac677d1fc"
 dependencies = [
  "cfg-if",
  "crossbeam-epoch",
@@ -138,26 +129,24 @@ dependencies = [
 
 [[package]]
 name = "crossbeam-epoch"
-version = "0.9.8"
+version = "0.9.13"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1145cf131a2c6ba0615079ab6a638f7e1973ac9c2634fcbeaaad6114246efe8c"
+checksum = "01a9af1f4c2ef74bb8aa1f7e19706bc72d03598c8a570bb5de72243c7a9d9d5a"
 dependencies = [
  "autocfg",
  "cfg-if",
  "crossbeam-utils",
- "lazy_static",
  "memoffset",
  "scopeguard",
 ]
 
 [[package]]
 name = "crossbeam-utils"
-version = "0.8.8"
+version = "0.8.14"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0bf124c720b7686e3c2663cf54062ab0f68a88af2fb6a030e87e30bf721fcb38"
+checksum = "4fb766fa798726286dbbb842f174001dab8abc7b627a1dd86e0b7222a95d929f"
 dependencies = [
  "cfg-if",
- "lazy_static",
 ]
 
 [[package]]
@@ -379,9 +368,9 @@ checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
 
 [[package]]
 name = "memoffset"
-version = "0.6.5"
+version = "0.7.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce"
+checksum = "5de893c32cde5f383baa4c04c5d6dbdd735cfd4a794b0debdb2bb1b421da5ff4"
 dependencies = [
  "autocfg",
 ]
@@ -447,14 +436,14 @@ checksum = "1df8c4ec4b0627e53bdf214615ad287367e482558cf84b109250b37464dc03ae"
 
 [[package]]
 name = "pretty_assertions"
-version = "0.7.2"
+version = "1.3.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1cab0e7c02cf376875e9335e0ba1da535775beb5450d21e1dffca068818ed98b"
+checksum = "a25e9bcb20aa780fd0bb16b72403a9064d6b3f22f026946029acb941a50af755"
 dependencies = [
- "ansi_term",
  "ctor",
  "diff",
  "output_vt100",
+ "yansi",
 ]
 
 [[package]]
@@ -477,11 +466,10 @@ dependencies = [
 
 [[package]]
 name = "rayon"
-version = "1.5.3"
+version = "1.6.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bd99e5772ead8baa5215278c9b15bf92087709e9c1b2d1f97cdb5a183c933a7d"
+checksum = "1e060280438193c554f654141c9ea9417886713b7acd75974c85b18a69a88e0b"
 dependencies = [
- "autocfg",
  "crossbeam-deque",
  "either",
  "rayon-core",
@@ -489,9 +477,9 @@ dependencies = [
 
 [[package]]
 name = "rayon-core"
-version = "1.9.3"
+version = "1.10.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "258bcdb5ac6dad48491bb2992db6b7cf74878b0384908af124823d118c99683f"
+checksum = "cac410af5d00ab6884528b4ab69d1e8e146e8d471201800fa1b4524126de6ad3"
 dependencies = [
  "crossbeam-channel",
  "crossbeam-deque",
@@ -803,3 +791,9 @@ checksum = "c179869f34fc7c01830d3ce7ea2086bc3a07e0d35289b667d0a8bf910258926c"
 dependencies = [
  "lzma-sys",
 ]
+
+[[package]]
+name = "yansi"
+version = "0.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec"
index 8751a71caf1b4957fc5688afdc259f14befb7576..ccc7ec1fce9f010d3842e31ba6e63b6ad4720efd 100644 (file)
@@ -72,7 +72,7 @@ features = [
 ]
 
 [dev-dependencies]
-pretty_assertions = "0.7"
+pretty_assertions = "1.2"
 
 [features]
 build-metrics = ["sysinfo"]
index cff5fd8c5b02cb46ea3656dfa548b87ae7b12dff..8ee6d49da8f0e419b4fc9ff2898a4e21f5c47bae 100644 (file)
@@ -754,6 +754,8 @@ macro_rules! describe {
                 run::BumpStage0,
                 run::ReplaceVersionPlaceholder,
                 run::Miri,
+                run::CollectLicenseMetadata,
+                run::GenerateCopyright,
             ),
             // These commands either don't use paths, or they're special-cased in Build::build()
             Kind::Clean | Kind::Format | Kind::Setup => vec![],
index babf09d2b93349605ed3c8b2965635e7932a352b..960fbdf75380448983b1f3650b9fd66b95dc3df8 100644 (file)
@@ -3,6 +3,9 @@
 //! This module implements parsing `config.toml` configuration files to tweak
 //! how the build runs.
 
+#[cfg(test)]
+mod tests;
+
 use std::cell::{Cell, RefCell};
 use std::cmp;
 use std::collections::{HashMap, HashSet};
@@ -213,6 +216,7 @@ pub struct Config {
     pub npm: Option<PathBuf>,
     pub gdb: Option<PathBuf>,
     pub python: Option<PathBuf>,
+    pub reuse: Option<PathBuf>,
     pub cargo_native_static: bool,
     pub configure_args: Vec<String>,
 
@@ -611,6 +615,7 @@ struct Build {
         nodejs: Option<String> = "nodejs",
         npm: Option<String> = "npm",
         python: Option<String> = "python",
+        reuse: Option<String> = "reuse",
         locked_deps: Option<bool> = "locked-deps",
         vendor: Option<bool> = "vendor",
         full_bootstrap: Option<bool> = "full-bootstrap",
@@ -694,7 +699,7 @@ struct Dist {
     }
 }
 
-#[derive(Deserialize)]
+#[derive(Debug, Deserialize)]
 #[serde(untagged)]
 enum StringOrBool {
     String(String),
@@ -820,6 +825,29 @@ pub fn default_opts() -> Config {
     }
 
     pub fn parse(args: &[String]) -> Config {
+        #[cfg(test)]
+        let get_toml = |_: &_| TomlConfig::default();
+        #[cfg(not(test))]
+        let get_toml = |file: &Path| {
+            let contents =
+                t!(fs::read_to_string(file), format!("config file {} not found", file.display()));
+            // Deserialize to Value and then TomlConfig to prevent the Deserialize impl of
+            // TomlConfig and sub types to be monomorphized 5x by toml.
+            match toml::from_str(&contents)
+                .and_then(|table: toml::Value| TomlConfig::deserialize(table))
+            {
+                Ok(table) => table,
+                Err(err) => {
+                    eprintln!("failed to parse TOML configuration '{}': {}", file.display(), err);
+                    crate::detail_exit(2);
+                }
+            }
+        };
+
+        Self::parse_inner(args, get_toml)
+    }
+
+    fn parse_inner<'a>(args: &[String], get_toml: impl 'a + Fn(&Path) -> TomlConfig) -> Config {
         let flags = Flags::parse(&args);
         let mut config = Config::default_opts();
 
@@ -905,25 +933,6 @@ pub fn parse(args: &[String]) -> Config {
 
         config.stage0_metadata = t!(serde_json::from_slice::<Stage0Metadata>(&stage0_json));
 
-        #[cfg(test)]
-        let get_toml = |_| TomlConfig::default();
-        #[cfg(not(test))]
-        let get_toml = |file: &Path| {
-            let contents =
-                t!(fs::read_to_string(file), format!("config file {} not found", file.display()));
-            // Deserialize to Value and then TomlConfig to prevent the Deserialize impl of
-            // TomlConfig and sub types to be monomorphized 5x by toml.
-            match toml::from_str(&contents)
-                .and_then(|table: toml::Value| TomlConfig::deserialize(table))
-            {
-                Ok(table) => table,
-                Err(err) => {
-                    eprintln!("failed to parse TOML configuration '{}': {}", file.display(), err);
-                    crate::detail_exit(2);
-                }
-            }
-        };
-
         // Read from `--config`, then `RUST_BOOTSTRAP_CONFIG`, then `./config.toml`, then `config.toml` in the root directory.
         let toml_path = flags
             .config
@@ -1004,6 +1013,7 @@ pub fn parse(args: &[String]) -> Config {
         config.npm = build.npm.map(PathBuf::from);
         config.gdb = build.gdb.map(PathBuf::from);
         config.python = build.python.map(PathBuf::from);
+        config.reuse = build.reuse.map(PathBuf::from);
         config.submodules = build.submodules;
         set(&mut config.low_priority, build.low_priority);
         set(&mut config.compiler_docs, build.compiler_docs);
@@ -1060,6 +1070,79 @@ pub fn parse(args: &[String]) -> Config {
         let mut optimize = None;
         let mut ignore_git = None;
 
+        if let Some(rust) = toml.rust {
+            debug = rust.debug;
+            debug_assertions = rust.debug_assertions;
+            debug_assertions_std = rust.debug_assertions_std;
+            overflow_checks = rust.overflow_checks;
+            overflow_checks_std = rust.overflow_checks_std;
+            debug_logging = rust.debug_logging;
+            debuginfo_level = rust.debuginfo_level;
+            debuginfo_level_rustc = rust.debuginfo_level_rustc;
+            debuginfo_level_std = rust.debuginfo_level_std;
+            debuginfo_level_tools = rust.debuginfo_level_tools;
+            debuginfo_level_tests = rust.debuginfo_level_tests;
+            config.rust_split_debuginfo = rust
+                .split_debuginfo
+                .as_deref()
+                .map(SplitDebuginfo::from_str)
+                .map(|v| v.expect("invalid value for rust.split_debuginfo"))
+                .unwrap_or(SplitDebuginfo::default_for_platform(&config.build.triple));
+            optimize = rust.optimize;
+            ignore_git = rust.ignore_git;
+            config.rust_new_symbol_mangling = rust.new_symbol_mangling;
+            set(&mut config.rust_optimize_tests, rust.optimize_tests);
+            set(&mut config.codegen_tests, rust.codegen_tests);
+            set(&mut config.rust_rpath, rust.rpath);
+            set(&mut config.jemalloc, rust.jemalloc);
+            set(&mut config.test_compare_mode, rust.test_compare_mode);
+            set(&mut config.backtrace, rust.backtrace);
+            set(&mut config.channel, rust.channel);
+            config.description = rust.description;
+            set(&mut config.rust_dist_src, rust.dist_src);
+            set(&mut config.verbose_tests, rust.verbose_tests);
+            // in the case "false" is set explicitly, do not overwrite the command line args
+            if let Some(true) = rust.incremental {
+                config.incremental = true;
+            }
+            set(&mut config.use_lld, rust.use_lld);
+            set(&mut config.lld_enabled, rust.lld);
+            set(&mut config.llvm_tools_enabled, rust.llvm_tools);
+            config.rustc_parallel = rust.parallel_compiler.unwrap_or(false);
+            config.rustc_default_linker = rust.default_linker;
+            config.musl_root = rust.musl_root.map(PathBuf::from);
+            config.save_toolstates = rust.save_toolstates.map(PathBuf::from);
+            set(&mut config.deny_warnings, flags.deny_warnings.or(rust.deny_warnings));
+            set(&mut config.backtrace_on_ice, rust.backtrace_on_ice);
+            set(&mut config.rust_verify_llvm_ir, rust.verify_llvm_ir);
+            config.rust_thin_lto_import_instr_limit = rust.thin_lto_import_instr_limit;
+            set(&mut config.rust_remap_debuginfo, rust.remap_debuginfo);
+            set(&mut config.control_flow_guard, rust.control_flow_guard);
+            config.llvm_libunwind_default = rust
+                .llvm_libunwind
+                .map(|v| v.parse().expect("failed to parse rust.llvm-libunwind"));
+
+            if let Some(ref backends) = rust.codegen_backends {
+                config.rust_codegen_backends =
+                    backends.iter().map(|s| INTERNER.intern_str(s)).collect();
+            }
+
+            config.rust_codegen_units = rust.codegen_units.map(threads_from_config);
+            config.rust_codegen_units_std = rust.codegen_units_std.map(threads_from_config);
+            config.rust_profile_use = flags.rust_profile_use.or(rust.profile_use);
+            config.rust_profile_generate = flags.rust_profile_generate.or(rust.profile_generate);
+            config.download_rustc_commit = config.download_ci_rustc_commit(rust.download_rustc);
+
+            config.rust_lto = rust
+                .lto
+                .as_deref()
+                .map(|value| RustcLto::from_str(value).unwrap())
+                .unwrap_or_default();
+        } else {
+            config.rust_profile_use = flags.rust_profile_use;
+            config.rust_profile_generate = flags.rust_profile_generate;
+        }
+
         if let Some(llvm) = toml.llvm {
             match llvm.ccache {
                 Some(StringOrBool::String(ref s)) => config.ccache = Some(s.to_string()),
@@ -1096,13 +1179,17 @@ pub fn parse(args: &[String]) -> Config {
             config.llvm_polly = llvm.polly.unwrap_or(false);
             config.llvm_clang = llvm.clang.unwrap_or(false);
             config.llvm_build_config = llvm.build_config.clone().unwrap_or(Default::default());
+
+            let asserts = llvm_assertions.unwrap_or(false);
             config.llvm_from_ci = match llvm.download_ci_llvm {
                 Some(StringOrBool::String(s)) => {
                     assert!(s == "if-available", "unknown option `{}` for download-ci-llvm", s);
-                    crate::native::is_ci_llvm_available(&config, llvm_assertions.unwrap_or(false))
+                    crate::native::is_ci_llvm_available(&config, asserts)
                 }
                 Some(StringOrBool::Bool(b)) => b,
-                None => false,
+                None => {
+                    config.channel == "dev" && crate::native::is_ci_llvm_available(&config, asserts)
+                }
             };
 
             if config.llvm_from_ci {
@@ -1142,79 +1229,9 @@ pub fn parse(args: &[String]) -> Config {
                 // the link step) with each stage.
                 config.llvm_link_shared.set(Some(true));
             }
-        }
-
-        if let Some(rust) = toml.rust {
-            debug = rust.debug;
-            debug_assertions = rust.debug_assertions;
-            debug_assertions_std = rust.debug_assertions_std;
-            overflow_checks = rust.overflow_checks;
-            overflow_checks_std = rust.overflow_checks_std;
-            debug_logging = rust.debug_logging;
-            debuginfo_level = rust.debuginfo_level;
-            debuginfo_level_rustc = rust.debuginfo_level_rustc;
-            debuginfo_level_std = rust.debuginfo_level_std;
-            debuginfo_level_tools = rust.debuginfo_level_tools;
-            debuginfo_level_tests = rust.debuginfo_level_tests;
-            config.rust_split_debuginfo = rust
-                .split_debuginfo
-                .as_deref()
-                .map(SplitDebuginfo::from_str)
-                .map(|v| v.expect("invalid value for rust.split_debuginfo"))
-                .unwrap_or(SplitDebuginfo::default_for_platform(&config.build.triple));
-            optimize = rust.optimize;
-            ignore_git = rust.ignore_git;
-            config.rust_new_symbol_mangling = rust.new_symbol_mangling;
-            set(&mut config.rust_optimize_tests, rust.optimize_tests);
-            set(&mut config.codegen_tests, rust.codegen_tests);
-            set(&mut config.rust_rpath, rust.rpath);
-            set(&mut config.jemalloc, rust.jemalloc);
-            set(&mut config.test_compare_mode, rust.test_compare_mode);
-            set(&mut config.backtrace, rust.backtrace);
-            set(&mut config.channel, rust.channel);
-            config.description = rust.description;
-            set(&mut config.rust_dist_src, rust.dist_src);
-            set(&mut config.verbose_tests, rust.verbose_tests);
-            // in the case "false" is set explicitly, do not overwrite the command line args
-            if let Some(true) = rust.incremental {
-                config.incremental = true;
-            }
-            set(&mut config.use_lld, rust.use_lld);
-            set(&mut config.lld_enabled, rust.lld);
-            set(&mut config.llvm_tools_enabled, rust.llvm_tools);
-            config.rustc_parallel = rust.parallel_compiler.unwrap_or(false);
-            config.rustc_default_linker = rust.default_linker;
-            config.musl_root = rust.musl_root.map(PathBuf::from);
-            config.save_toolstates = rust.save_toolstates.map(PathBuf::from);
-            set(&mut config.deny_warnings, flags.deny_warnings.or(rust.deny_warnings));
-            set(&mut config.backtrace_on_ice, rust.backtrace_on_ice);
-            set(&mut config.rust_verify_llvm_ir, rust.verify_llvm_ir);
-            config.rust_thin_lto_import_instr_limit = rust.thin_lto_import_instr_limit;
-            set(&mut config.rust_remap_debuginfo, rust.remap_debuginfo);
-            set(&mut config.control_flow_guard, rust.control_flow_guard);
-            config.llvm_libunwind_default = rust
-                .llvm_libunwind
-                .map(|v| v.parse().expect("failed to parse rust.llvm-libunwind"));
-
-            if let Some(ref backends) = rust.codegen_backends {
-                config.rust_codegen_backends =
-                    backends.iter().map(|s| INTERNER.intern_str(s)).collect();
-            }
-
-            config.rust_codegen_units = rust.codegen_units.map(threads_from_config);
-            config.rust_codegen_units_std = rust.codegen_units_std.map(threads_from_config);
-            config.rust_profile_use = flags.rust_profile_use.or(rust.profile_use);
-            config.rust_profile_generate = flags.rust_profile_generate.or(rust.profile_generate);
-            config.download_rustc_commit = config.download_ci_rustc_commit(rust.download_rustc);
-
-            config.rust_lto = rust
-                .lto
-                .as_deref()
-                .map(|value| RustcLto::from_str(value).unwrap())
-                .unwrap_or_default();
         } else {
-            config.rust_profile_use = flags.rust_profile_use;
-            config.rust_profile_generate = flags.rust_profile_generate;
+            config.llvm_from_ci =
+                config.channel == "dev" && crate::native::is_ci_llvm_available(&config, false);
         }
 
         if let Some(t) = toml.target {
diff --git a/src/bootstrap/config/tests.rs b/src/bootstrap/config/tests.rs
new file mode 100644 (file)
index 0000000..c30c913
--- /dev/null
@@ -0,0 +1,24 @@
+use super::{Config, TomlConfig};
+use std::path::Path;
+
+fn toml(config: &str) -> impl '_ + Fn(&Path) -> TomlConfig {
+    |&_| toml::from_str(config).unwrap()
+}
+
+fn parse(config: &str) -> Config {
+    Config::parse_inner(&["check".to_owned(), "--config=/does/not/exist".to_owned()], toml(config))
+}
+
+#[test]
+fn download_ci_llvm() {
+    let parse_llvm = |s| parse(s).llvm_from_ci;
+    let if_available = parse_llvm("llvm.download-ci-llvm = \"if-available\"");
+
+    assert!(parse_llvm("llvm.download-ci-llvm = true"));
+    assert!(!parse_llvm("llvm.download-ci-llvm = false"));
+    assert_eq!(parse_llvm(""), if_available);
+    assert_eq!(parse_llvm("rust.channel = \"dev\""), if_available);
+    assert!(!parse_llvm("rust.channel = \"stable\""));
+}
+
+// FIXME: add test for detecting `src` and `out`
index 6647061d88fcbc99005ed446871d4ab2c420273c..48ae2fe448de2070ddcfd37b57b99434386b5ba4 100644 (file)
@@ -7,3 +7,7 @@ test-stage = 2
 doc-stage = 2
 # When compiling from source, you usually want all tools.
 extended = true
+
+[llvm]
+# Most users installing from source want to build all parts of the project from source, not just rustc itself.
+download-ci-llvm = false
index 2001e29bd2eadc56759de805020fb83fc86cdc25..37a8eb884efb02beba7ca57c462108a1bca96ae1 100644 (file)
@@ -143,7 +143,7 @@ pub enum Subcommand {
         args: Vec<String>,
     },
     Setup {
-        profile: Profile,
+        profile: Option<Profile>,
     },
 }
 
@@ -628,14 +628,15 @@ pub fn parse(args: &[String]) -> Flags {
                         |path| format!("{} is not a valid UTF8 string", path.to_string_lossy())
                     ));
 
-                    profile_string.parse().unwrap_or_else(|err| {
+                    let profile = profile_string.parse().unwrap_or_else(|err| {
                         eprintln!("error: {}", err);
                         eprintln!("help: the available profiles are:");
                         eprint!("{}", Profile::all_for_help("- "));
                         crate::detail_exit(1);
-                    })
+                    });
+                    Some(profile)
                 } else {
-                    t!(crate::setup::interactive_path())
+                    None
                 };
                 Subcommand::Setup { profile }
             }
index a3d1893afbb65d171eb8052773a757978e5f75c1..570fe6484e3db32aa436633f4ebde35d369b57a0 100644 (file)
@@ -542,16 +542,6 @@ pub fn new(mut config: Config) -> Build {
             metrics: metrics::BuildMetrics::init(),
         };
 
-        build.verbose("finding compilers");
-        cc_detect::find(&mut build);
-        // When running `setup`, the profile is about to change, so any requirements we have now may
-        // be different on the next invocation. Don't check for them until the next time x.py is
-        // run. This is ok because `setup` never runs any build commands, so it won't fail if commands are missing.
-        if !matches!(build.config.cmd, Subcommand::Setup { .. }) {
-            build.verbose("running sanity check");
-            sanity::check(&mut build);
-        }
-
         // If local-rust is the same major.minor as the current version, then force a
         // local-rebuild
         let local_version_verbose =
@@ -567,16 +557,34 @@ pub fn new(mut config: Config) -> Build {
             build.local_rebuild = true;
         }
 
-        // Make sure we update these before gathering metadata so we don't get an error about missing
-        // Cargo.toml files.
-        let rust_submodules =
-            ["src/tools/rust-installer", "src/tools/cargo", "library/backtrace", "library/stdarch"];
-        for s in rust_submodules {
-            build.update_submodule(Path::new(s));
-        }
+        build.verbose("finding compilers");
+        cc_detect::find(&mut build);
+        // When running `setup`, the profile is about to change, so any requirements we have now may
+        // be different on the next invocation. Don't check for them until the next time x.py is
+        // run. This is ok because `setup` never runs any build commands, so it won't fail if commands are missing.
+        //
+        // Similarly, for `setup` we don't actually need submodules or cargo metadata.
+        if !matches!(build.config.cmd, Subcommand::Setup { .. }) {
+            build.verbose("running sanity check");
+            sanity::check(&mut build);
 
-        build.verbose("learning about cargo");
-        metadata::build(&mut build);
+            // Make sure we update these before gathering metadata so we don't get an error about missing
+            // Cargo.toml files.
+            let rust_submodules = [
+                "src/tools/rust-installer",
+                "src/tools/cargo",
+                "library/backtrace",
+                "library/stdarch",
+            ];
+            for s in rust_submodules {
+                build.update_submodule(Path::new(s));
+            }
+            // Now, update all existing submodules.
+            build.update_existing_submodules();
+
+            build.verbose("learning about cargo");
+            metadata::build(&mut build);
+        }
 
         build
     }
@@ -647,15 +655,28 @@ fn dir_is_empty(dir: &Path) -> bool {
         if !update(true).status().map_or(false, |status| status.success()) {
             self.run(&mut update(false));
         }
-        self.run(Command::new("git").args(&["stash", "push"]).current_dir(&absolute_path));
+
+        // Save any local changes, but avoid running `git stash pop` if there are none (since it will exit with an error).
+        let has_local_modifications = !self.try_run(
+            Command::new("git")
+                .args(&["diff-index", "--quiet", "HEAD"])
+                .current_dir(&absolute_path),
+        );
+        if has_local_modifications {
+            self.run(Command::new("git").args(&["stash", "push"]).current_dir(&absolute_path));
+        }
+
         self.run(Command::new("git").args(&["reset", "-q", "--hard"]).current_dir(&absolute_path));
         self.run(Command::new("git").args(&["clean", "-qdfx"]).current_dir(&absolute_path));
-        self.run(Command::new("git").args(&["stash", "pop"]).current_dir(absolute_path));
+
+        if has_local_modifications {
+            self.run(Command::new("git").args(&["stash", "pop"]).current_dir(absolute_path));
+        }
     }
 
     /// If any submodule has been initialized already, sync it unconditionally.
     /// This avoids contributors checking in a submodule change by accident.
-    pub fn maybe_update_submodules(&self) {
+    pub fn update_existing_submodules(&self) {
         // Avoid running git when there isn't a git checkout.
         if !self.config.submodules(&self.rust_info()) {
             return;
@@ -684,8 +705,6 @@ pub fn build(&mut self) {
             job::setup(self);
         }
 
-        self.maybe_update_submodules();
-
         if let Subcommand::Format { check, paths } = &self.config.cmd {
             return format::format(&builder::Builder::new(&self), *check, &paths);
         }
@@ -1620,10 +1639,10 @@ fn chmod(_path: &Path, _perms: u32) {}
 /// 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 status code provided
-    if cfg!(test) && code != 0 {
+    if cfg!(test) {
         panic!("status code: {}", code);
     } else {
-        //otherwise,exit with provided status code
+        // otherwise,exit with provided status code
         std::process::exit(code);
     }
 }
index d49b41c51327961203f561254a85ef0ffad7346e..05de51f8cc57933b886fb6a7b1d2436e4c728316 100644 (file)
@@ -1,3 +1,4 @@
+use std::path::PathBuf;
 use std::process::Command;
 
 use crate::builder::{Builder, RunConfig, ShouldRun, Step};
@@ -189,3 +190,65 @@ fn run(self, builder: &Builder<'_>) {
         builder.run(&mut miri);
     }
 }
+
+#[derive(Debug, PartialOrd, Ord, Copy, Clone, Hash, PartialEq, Eq)]
+pub struct CollectLicenseMetadata;
+
+impl Step for CollectLicenseMetadata {
+    type Output = PathBuf;
+    const ONLY_HOSTS: bool = true;
+
+    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
+        run.path("src/tools/collect-license-metadata")
+    }
+
+    fn make_run(run: RunConfig<'_>) {
+        run.builder.ensure(CollectLicenseMetadata);
+    }
+
+    fn run(self, builder: &Builder<'_>) -> Self::Output {
+        let Some(reuse) = &builder.config.reuse else {
+            panic!("REUSE is required to collect the license metadata");
+        };
+
+        // Temporary location, it will be moved to src/etc once it's accurate.
+        let dest = builder.out.join("license-metadata.json");
+
+        let mut cmd = builder.tool_cmd(Tool::CollectLicenseMetadata);
+        cmd.env("REUSE_EXE", reuse);
+        cmd.env("DEST", &dest);
+        builder.run(&mut cmd);
+
+        dest
+    }
+}
+
+#[derive(Debug, PartialOrd, Ord, Copy, Clone, Hash, PartialEq, Eq)]
+pub struct GenerateCopyright;
+
+impl Step for GenerateCopyright {
+    type Output = PathBuf;
+    const ONLY_HOSTS: bool = true;
+
+    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
+        run.path("src/tools/generate-copyright")
+    }
+
+    fn make_run(run: RunConfig<'_>) {
+        run.builder.ensure(GenerateCopyright);
+    }
+
+    fn run(self, builder: &Builder<'_>) -> Self::Output {
+        let license_metadata = builder.ensure(CollectLicenseMetadata);
+
+        // Temporary location, it will be moved to the proper one once it's accurate.
+        let dest = builder.out.join("COPYRIGHT.md");
+
+        let mut cmd = builder.tool_cmd(Tool::GenerateCopyright);
+        cmd.env("LICENSE_METADATA", &license_metadata);
+        cmd.env("DEST", &dest);
+        builder.run(&mut cmd);
+
+        dest
+    }
+}
index 631d42acb93fc3564093496169d0a9b4012a9166..8a40b0f64f4b6c5673ce6fc1c885f4622958c0e0 100644 (file)
@@ -140,6 +140,13 @@ pub fn check(build: &mut Build) {
         .map(|p| cmd_finder.must_have(p))
         .or_else(|| cmd_finder.maybe_have("gdb"));
 
+    build.config.reuse = build
+        .config
+        .reuse
+        .take()
+        .map(|p| cmd_finder.must_have(p))
+        .or_else(|| cmd_finder.maybe_have("reuse"));
+
     // We're gonna build some custom C code here and there, host triples
     // also build some C++ shims for LLVM so we need a C++ compiler.
     for target in &build.targets {
index 04480277fe0474cb8b3dd97993d8f4bdaf1162e0..c7f98a7d0d149ae28c21ad6dadb109034e9bbff6 100644 (file)
@@ -1,15 +1,13 @@
+use crate::Config;
 use crate::{t, VERSION};
-use crate::{Config, TargetSelection};
 use std::env::consts::EXE_SUFFIX;
 use std::fmt::Write as _;
 use std::fs::File;
+use std::io::Write;
 use std::path::{Path, PathBuf, MAIN_SEPARATOR};
 use std::process::Command;
 use std::str::FromStr;
-use std::{
-    env, fmt, fs,
-    io::{self, Write},
-};
+use std::{fmt, fs, io};
 
 #[derive(Clone, Copy, Debug, Eq, PartialEq)]
 pub enum Profile {
@@ -81,38 +79,10 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
     }
 }
 
-pub fn setup(config: &Config, profile: Profile) {
-    let path = &config.config.clone().unwrap_or(PathBuf::from("config.toml"));
-
-    if path.exists() {
-        eprintln!(
-            "error: you asked `x.py` to setup a new config file, but one already exists at `{}`",
-            path.display()
-        );
-        eprintln!("help: try adding `profile = \"{}\"` at the top of {}", profile, path.display());
-        eprintln!(
-            "note: this will use the configuration in {}",
-            profile.include_path(&config.src).display()
-        );
-        crate::detail_exit(1);
-    }
-
-    let settings = format!(
-        "# Includes one of the default files in src/bootstrap/defaults\n\
-    profile = \"{}\"\n\
-    changelog-seen = {}\n",
-        profile, VERSION
-    );
-    t!(fs::write(path, settings));
-
-    let include_path = profile.include_path(&config.src);
-    println!("`x.py` will now use the configuration at {}", include_path.display());
-
-    let build = TargetSelection::from_user(&env!("BUILD_TRIPLE"));
+pub fn setup(config: &Config, profile: Option<Profile>) {
+    let profile = profile.unwrap_or_else(|| t!(interactive_path()));
     let stage_path =
-        ["build", build.rustc_target_arg(), "stage1"].join(&MAIN_SEPARATOR.to_string());
-
-    println!();
+        ["build", config.build.rustc_target_arg(), "stage1"].join(&MAIN_SEPARATOR.to_string());
 
     if !rustup_installed() && profile != Profile::User {
         eprintln!("`rustup` is not installed; cannot link `stage1` toolchain");
@@ -134,8 +104,6 @@ pub fn setup(config: &Config, profile: Profile) {
         Profile::User => &["dist", "build"],
     };
 
-    println!();
-
     t!(install_git_hook_maybe(&config));
 
     println!();
@@ -150,6 +118,36 @@ pub fn setup(config: &Config, profile: Profile) {
             "For more suggestions, see https://rustc-dev-guide.rust-lang.org/building/suggested.html"
         );
     }
+
+    let path = &config.config.clone().unwrap_or(PathBuf::from("config.toml"));
+    setup_config_toml(path, profile, config);
+}
+
+fn setup_config_toml(path: &PathBuf, profile: Profile, config: &Config) {
+    if path.exists() {
+        eprintln!();
+        eprintln!(
+            "error: you asked `x.py` to setup a new config file, but one already exists at `{}`",
+            path.display()
+        );
+        eprintln!("help: try adding `profile = \"{}\"` at the top of {}", profile, path.display());
+        eprintln!(
+            "note: this will use the configuration in {}",
+            profile.include_path(&config.src).display()
+        );
+        crate::detail_exit(1);
+    }
+
+    let settings = format!(
+        "# Includes one of the default files in src/bootstrap/defaults\n\
+    profile = \"{}\"\n\
+    changelog-seen = {}\n",
+        profile, VERSION
+    );
+    t!(fs::write(path, settings));
+
+    let include_path = profile.include_path(&config.src);
+    println!("`x.py` will now use the configuration at {}", include_path.display());
 }
 
 fn rustup_installed() -> bool {
@@ -303,7 +301,18 @@ fn parse_with_abbrev(input: &str) -> Result<Profile, String> {
 
 // install a git hook to automatically run tidy --bless, if they want
 fn install_git_hook_maybe(config: &Config) -> io::Result<()> {
+    let git = t!(config.git().args(&["rev-parse", "--git-common-dir"]).output().map(|output| {
+        assert!(output.status.success(), "failed to run `git`");
+        PathBuf::from(t!(String::from_utf8(output.stdout)).trim())
+    }));
+    let dst = git.join("hooks").join("pre-push");
+    if dst.exists() {
+        // The git hook has already been set up, or the user already has a custom hook.
+        return Ok(());
+    }
+
     let mut input = String::new();
+    println!();
     println!(
         "Rust's CI will automatically fail if it doesn't pass `tidy`, the internal tool for ensuring code quality.
 If you'd like, x.py can install a git hook for you that will automatically run `tidy --bless` before
@@ -329,12 +338,6 @@ fn install_git_hook_maybe(config: &Config) -> io::Result<()> {
 
     if should_install {
         let src = config.src.join("src").join("etc").join("pre-push.sh");
-        let git =
-            t!(config.git().args(&["rev-parse", "--git-common-dir"]).output().map(|output| {
-                assert!(output.status.success(), "failed to run `git`");
-                PathBuf::from(t!(String::from_utf8(output.stdout)).trim())
-            }));
-        let dst = git.join("hooks").join("pre-push");
         match fs::hard_link(src, &dst) {
             Err(e) => eprintln!(
                 "error: could not create hook {}: do you already have the git hook installed?\n{}",
index ba329ea6c759286e37140469dded952b5dcf2850..24b033cc0dc5eb4f6e63104efc065a507d35a114 100644 (file)
@@ -380,6 +380,8 @@ fn run(self, builder: &Builder<'_>) -> PathBuf {
     HtmlChecker, "src/tools/html-checker", "html-checker";
     BumpStage0, "src/tools/bump-stage0", "bump-stage0";
     ReplaceVersionPlaceholder, "src/tools/replace-version-placeholder", "replace-version-placeholder";
+    CollectLicenseMetadata, "src/tools/collect-license-metadata", "collect-license-metadata";
+    GenerateCopyright, "src/tools/generate-copyright", "generate-copyright";
 );
 
 #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, Ord, PartialOrd)]
@@ -745,19 +747,9 @@ impl Step for RustAnalyzerProcMacroSrv {
     const ONLY_HOSTS: bool = true;
 
     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
-        let builder = run.builder;
-
         // Allow building `rust-analyzer-proc-macro-srv` both as part of the `rust-analyzer` and as a stand-alone tool.
         run.path("src/tools/rust-analyzer")
             .path("src/tools/rust-analyzer/crates/proc-macro-srv-cli")
-            .default_condition(
-                builder.config.extended
-                    && builder.config.tools.as_ref().map_or(true, |tools| {
-                        tools.iter().any(|tool| {
-                            tool == "rust-analyzer" || tool == "rust-analyzer-proc-macro-srv"
-                        })
-                    }),
-            )
     }
 
     fn make_run(run: RunConfig<'_>) {
index e54d0eafb4003abb4575ad858734cffa5540d2bd..699938c37184285eef21b68354f85efd3455f03f 100644 (file)
@@ -14,7 +14,8 @@ RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y --no-ins
   gdb \
   libssl-dev \
   pkg-config \
-  xz-utils
+  xz-utils \
+  && rm -rf /var/lib/apt/lists/*
 
 COPY scripts/sccache.sh /scripts/
 RUN sh /scripts/sccache.sh
index cd86d9fb584fb116eaeb6345f841fe7718846754..ea4a2a2427dbf8ba29e66719bbd6d4163fb0b340 100644 (file)
@@ -32,7 +32,8 @@ RUN yum upgrade -y && \
       wget \
       xz \
       zlib-devel.i686 \
-      zlib-devel.x86_64
+      zlib-devel.x86_64 \
+      && yum clean all
 
 RUN mkdir -p /rustroot/bin && ln -s /usr/bin/cmake3 /rustroot/bin/cmake
 
index 9a290edd561cc7a6eccb1dd7fd01cb77f67a4f52..6b7b32a8bc77f85c4a7eb5b84892d9b5cbfae844 100644 (file)
@@ -24,5 +24,5 @@ ENV \
 
 ENV HOSTS=powerpc64le-unknown-linux-gnu
 
-ENV RUST_CONFIGURE_ARGS --enable-extended --disable-docs
+ENV RUST_CONFIGURE_ARGS --enable-extended --enable-profiler --disable-docs
 ENV SCRIPT python3 ../x.py dist --host $HOSTS --target $HOSTS
index 36c94458da7bd422c307f8008239bff6bfffc18d..67cee0148b24ec4cbb9a3e47f1aa379879106319 100755 (executable)
@@ -2,15 +2,15 @@
 
 set -ex
 
-# Originally from https://github.com/llvm/llvm-project/releases/download/llvmorg-14.0.0/clang+llvm-14.0.0-x86_64-linux-gnu-ubuntu-18.04.tar.xz
-curl https://ci-mirrors.rust-lang.org/rustc/2022-05-10-clang%2Bllvm-14.0.0-x86_64-linux-gnu-ubuntu-18.04.tar.xz | \
+# Originally from https://github.com/llvm/llvm-project/releases/download/llvmorg-15.0.6/clang+llvm-15.0.6-x86_64-linux-gnu-ubuntu-18.04.tar.xz
+curl https://ci-mirrors.rust-lang.org/rustc/2022-12-06-clang%2Bllvm-15.0.6-x86_64-linux-gnu-ubuntu-18.04.tar.xz | \
   tar xJf -
-bin="$PWD/clang+llvm-14.0.0-x86_64-linux-gnu-ubuntu-18.04/bin"
+bin="$PWD/clang+llvm-15.0.6-x86_64-linux-gnu-ubuntu-18.04/bin"
 
 git clone https://github.com/WebAssembly/wasi-libc
 
 cd wasi-libc
-git reset --hard 9886d3d6200fcc3726329966860fc058707406cd
+git reset --hard 8b7148f69ae241a2749b3defe4606da8143b72e0
 make -j$(nproc) \
     CC="$bin/clang" \
     NM="$bin/llvm-nm" \
index f9b1fa8951adff3b88b7017a77d420800ba8fb1f..377d4a9ce5ebde94f3ef2a56a24c890d8071908e 100644 (file)
@@ -15,7 +15,8 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
   xz-utils \
   wget \
   libssl-dev \
-  pkg-config
+  pkg-config \
+  && rm -rf /var/lib/apt/lists/*
 
 COPY scripts/freebsd-toolchain.sh /tmp/
 RUN /tmp/freebsd-toolchain.sh x86_64
index c2e44ead51ee4cdbe9e0a33150c7de5726447221..4e46bdee5acb581e412ec6b4f9a7313dc3abb245 100644 (file)
@@ -11,7 +11,8 @@ RUN apt-get update && \
     apt-get install -y --no-install-recommends \
       libgmp-dev \
       libmpfr-dev \
-      libmpc-dev
+      libmpc-dev \
+      && rm -rf /var/lib/apt/lists/*
 
 COPY scripts/illumos-toolchain.sh /tmp/
 
index 423aba06ccaff770963f392024b994368997a59d..6bdc88e18f530f8d9e2dc64ce6f41564a354c65f 100644 (file)
@@ -32,7 +32,8 @@ RUN yum upgrade -y && \
       wget \
       xz \
       zlib-devel.i686 \
-      zlib-devel.x86_64
+      zlib-devel.x86_64 \
+      && yum clean all
 
 RUN mkdir -p /rustroot/bin && ln -s /usr/bin/cmake3 /rustroot/bin/cmake
 
index 51645a81853fdf03cf6fa8e89c3bb2f9b8e7202c..13eaf7fce8cd76ae1a921b9dbdafb447537dde9f 100644 (file)
@@ -16,7 +16,8 @@ RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y --no-ins
   gdb \
   patch \
   libssl-dev \
-  pkg-config
+  pkg-config \
+  && rm -rf /var/lib/apt/lists/*
 
 WORKDIR /build/
 
index dd74726f856915a73311b92112066fe976d6e34a..e2b66c2cff1d8258e6721013559367b499e1005c 100644 (file)
@@ -15,7 +15,8 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
   gdb \
   zlib1g-dev \
   lib32z1-dev \
-  xz-utils
+  xz-utils \
+  && rm -rf /var/lib/apt/lists/*
 
 
 COPY scripts/sccache.sh /scripts/
index 0c36cfd66bdef05ac0842102035c2288fc84b271..cb6559707d962b53ab03f97515b1a9a68cd53425 100644 (file)
@@ -15,7 +15,8 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
   gdb \
   zlib1g-dev \
   lib32z1-dev \
-  xz-utils
+  xz-utils \
+  && rm -rf /var/lib/apt/lists/*
 
 
 COPY scripts/sccache.sh /scripts/
index 52a7776153dac353e3d2ca72f95a13958efff3dc..40caa7c50135d31dae92b8331501572436f874dd 100644 (file)
@@ -20,20 +20,20 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
   xz-utils \
   libssl-dev \
   pkg-config \
-  mingw-w64
+  mingw-w64 \
+  && rm -rf /var/lib/apt/lists/*
 
 RUN curl -sL https://nodejs.org/dist/v16.9.0/node-v16.9.0-linux-x64.tar.xz | tar -xJ
 ENV PATH="/node-v16.9.0-linux-x64/bin:${PATH}"
 # Install es-check
 # Pin its version to prevent unrelated CI failures due to future es-check versions.
-RUN npm install es-check@6.1.1 -g
-RUN npm install eslint@8.6.0 -g
+RUN npm install es-check@6.1.1 eslint@8.6.0 -g
 
 COPY scripts/sccache.sh /scripts/
 RUN sh /scripts/sccache.sh
 
 COPY host-x86_64/mingw-check/reuse-requirements.txt /tmp/
-RUN pip3 install --no-deps --require-hashes -r /tmp/reuse-requirements.txt
+RUN pip3 install --no-deps --no-cache-dir --require-hashes -r /tmp/reuse-requirements.txt
 
 COPY host-x86_64/mingw-check/validate-toolstate.sh /scripts/
 COPY host-x86_64/mingw-check/validate-error-codes.sh /scripts/
index 7c09e3a582fd6042c3a90f47c959b718772684ba..cf4451f8b33b64faa99c717e4ccb6f340b6014fb 100644 (file)
@@ -21,7 +21,8 @@ RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y --no-ins
   ovmf \
   qemu-efi-aarch64 \
   qemu-system-arm \
-  qemu-system-x86
+  qemu-system-x86 \
+  && rm -rf /var/lib/apt/lists/*
 
 RUN curl -sL https://nodejs.org/dist/v15.14.0/node-v15.14.0-linux-x64.tar.xz | \
   tar -xJ
index 9e37c2822e8bd58d5d166c7c2bc60832f0221a76..ef1fde1c3b924711c29829f75df0d1f89880e3dd 100644 (file)
@@ -13,7 +13,8 @@ RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y --no-ins
   sudo \
   gdb \
   xz-utils \
-  bzip2
+  bzip2 \
+  && rm -rf /var/lib/apt/lists/*
 
 COPY scripts/emscripten.sh /scripts/
 RUN bash /scripts/emscripten.sh
index d55d5b56ad3f5e8cccfced590d0d2c0a81dcbf0f..e08c4e1e8b7dec7c07fc11c9791e70b528b36554 100644 (file)
@@ -19,7 +19,8 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
   llvm-dev \
   libfreetype6-dev \
   libexpat1-dev \
-  tidy
+  tidy \
+  && rm -rf /var/lib/apt/lists/*
 
 COPY scripts/sccache.sh /scripts/
 RUN sh /scripts/sccache.sh
index 739045248fea205d7c0ef0ec80fffc6f71fc6af3..c2b002055a8fcc9c6176fbf16986c3b2e4b66a55 100644 (file)
@@ -23,7 +23,8 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
   pkg-config \
   xz-utils \
   lld \
-  clang
+  clang \
+  && rm -rf /var/lib/apt/lists/*
 
 COPY scripts/sccache.sh /scripts/
 RUN sh /scripts/sccache.sh
index 80a004501a81bb590553c4d77e8861587f331d07..7e640c49f015a4a413fc657b7f2567164b7ad5eb 100644 (file)
@@ -15,7 +15,8 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
   gdb \
   xz-utils \
   libssl-dev \
-  pkg-config
+  pkg-config \
+  && rm -rf /var/lib/apt/lists/*
 
 COPY scripts/sccache.sh /scripts/
 RUN sh /scripts/sccache.sh
index 23f2215c2d93cfbe85e3e06028f00793c96af05d..16976a9428ef1ebd3e8b4c34ffea94740ef7afdd 100644 (file)
@@ -21,7 +21,8 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
     pkg-config \
     zlib1g-dev \
     xz-utils \
-    nodejs
+    nodejs \
+    && rm -rf /var/lib/apt/lists/*
 
 COPY scripts/sccache.sh /scripts/
 RUN sh /scripts/sccache.sh
index 8f6831bc54e63e6b693c031ab6d7cda8f701d7e8..06f15bd121174eb5a195056bf12e75bfab390775 100644 (file)
@@ -24,15 +24,15 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
   pkg-config \
   zlib1g-dev \
   xz-utils \
-  nodejs
-
+  nodejs \
+  \
 # Install powershell so we can test x.ps1 on Linux
-RUN apt-get update && \
-    apt-get install -y apt-transport-https software-properties-common && \
+    apt-transport-https software-properties-common && \
     curl -s "https://packages.microsoft.com/config/ubuntu/$(lsb_release -rs)/packages-microsoft-prod.deb" > packages-microsoft-prod.deb && \
     dpkg -i packages-microsoft-prod.deb && \
     apt-get update && \
-    apt-get install -y powershell
+    apt-get install -y powershell \
+    && rm -rf /var/lib/apt/lists/*
 
 COPY scripts/sccache.sh /scripts/
 RUN sh /scripts/sccache.sh
index 77510d7ac62dc830d6550a6ce80df58763091cf3..9fdc78406fbd1f0f04f69c9006f6f32fe37ea820 100644 (file)
@@ -15,7 +15,8 @@ RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y --no-ins
   gdb \
   libssl-dev \
   pkg-config \
-  xz-utils
+  xz-utils \
+  && rm -rf /var/lib/apt/lists/*
 
 COPY scripts/sccache.sh /scripts/
 RUN sh /scripts/sccache.sh
index 4350ca205862ce742923d79c642b2511ad19f955..58c0c5db1a5d613a962e15ec93002e0e13b0a0bc 100644 (file)
@@ -14,10 +14,9 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
   libssl-dev \
   sudo \
   xz-utils \
-  tidy
-
+  tidy \
+  \
 # Install dependencies for chromium browser
-RUN apt-get install -y \
   gconf-service \
   libasound2 \
   libatk1.0-0 \
@@ -56,7 +55,8 @@ RUN apt-get install -y \
   libnss3 \
   lsb-release \
   xdg-utils \
-  wget
+  wget \
+  && rm -rf /var/lib/apt/lists/*
 
 COPY scripts/sccache.sh /scripts/
 RUN sh /scripts/sccache.sh
index 88c182a4d431fb6f01618297fa33873a120bfa6f..5b9581f72a64ef63dcc2df31a5100efe82fb83fc 100644 (file)
@@ -15,7 +15,8 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
   gdb \
   libssl-dev \
   pkg-config \
-  xz-utils
+  xz-utils \
+  && rm -rf /var/lib/apt/lists/*
 
 COPY scripts/sccache.sh /scripts/
 RUN sh /scripts/sccache.sh
index 4a4cac1b723c7db85dfc8d6c2099512aa97286a3..17cd456b995a1fcccd4970777a693ef7cc81bfba 100755 (executable)
@@ -53,7 +53,7 @@ files_to_extract=(
 for lib in c cxxrt gcc_s m thr util; do
   files_to_extract=("${files_to_extract[@]}" "./lib/lib${lib}.*" "./usr/lib/lib${lib}.*")
 done
-for lib in c++ c_nonshared compiler_rt execinfo gcc pthread rt ssp_nonshared procstat devstat kvm; do
+for lib in c++ c_nonshared compiler_rt execinfo gcc pthread rt ssp_nonshared procstat devstat kvm memstat; do
   files_to_extract=("${files_to_extract[@]}" "./usr/lib/lib${lib}.*")
 done
 
index 10de2e8d5eaa89f71d8f68874fed5db6696211c1..d1ba46ad30de6d08c82176a41b7e894c87358704 100644 (file)
@@ -77,7 +77,7 @@ x--expand-yaml-anchors--remove:
     <<: *base-job
 
   - &job-macos-xl
-    os: macos-latest  # We don't have an XL builder for this
+    os: macos-12-xl
     <<: *base-job
 
   - &job-windows-xl
@@ -467,7 +467,7 @@ jobs:
           - name: dist-x86_64-apple
             env:
               SCRIPT: ./x.py dist bootstrap --include-default-paths --host=x86_64-apple-darwin --target=x86_64-apple-darwin
-              RUST_CONFIGURE_ARGS: --enable-full-tools --enable-sanitizers --enable-profiler --set rust.jemalloc --set llvm.ninja=false
+              RUST_CONFIGURE_ARGS: --enable-full-tools --enable-sanitizers --enable-profiler --set rust.jemalloc --set llvm.ninja=false --set rust.lto=thin
               RUSTC_RETRY_LINKER_ON_SEGFAULT: 1
               MACOSX_DEPLOYMENT_TARGET: 10.7
               SELECT_XCODE: /Applications/Xcode_13.4.1.app
@@ -667,6 +667,7 @@ jobs:
                 --target=x86_64-pc-windows-msvc
                 --enable-full-tools
                 --enable-profiler
+                --set rust.lto=thin
               SCRIPT: PGO_HOST=x86_64-pc-windows-msvc src/ci/pgo.sh python x.py dist bootstrap --include-default-paths
               DIST_REQUIRE_ALL_TOOLS: 1
             <<: *job-windows-xl
index 3f64052c048c6def93b94a2b514ee88bba918744..a60f4316ec923a5ac2ed6a2eba6960edb832d855 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 3f64052c048c6def93b94a2b514ee88bba918744
+Subproject commit a60f4316ec923a5ac2ed6a2eba6960edb832d855
index c533348edd69f11a8f4225d633a05d7093fddbf3..19f798d448835a4888e3b3eae7fe69f1d61d8681 160000 (submodule)
@@ -1 +1 @@
-Subproject commit c533348edd69f11a8f4225d633a05d7093fddbf3
+Subproject commit 19f798d448835a4888e3b3eae7fe69f1d61d8681
index 05532356e7a4dbea2330aabb77611f5179493bb8..ae406aa5287a9e025abb72343aaceec98458c117 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 05532356e7a4dbea2330aabb77611f5179493bb8
+Subproject commit ae406aa5287a9e025abb72343aaceec98458c117
index 9f0cc13ffcd27c1fbe1ab766a9491e15ddcf4d19..3ae62681ff236d5528ef7c8c28ba7c6b2ecc6731 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 9f0cc13ffcd27c1fbe1ab766a9491e15ddcf4d19
+Subproject commit 3ae62681ff236d5528ef7c8c28ba7c6b2ecc6731
index 2b15c0abf2bada6e00553814336bc3e2d8399097..a9869b4a3c4cac3bc6099b41f088679e268400b8 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 2b15c0abf2bada6e00553814336bc3e2d8399097
+Subproject commit a9869b4a3c4cac3bc6099b41f088679e268400b8
index d0dc6c97a6486f68bac782fff135086eae6d77ec..e269950a57fa6fcda356426545fb5aa3691a7ced 160000 (submodule)
@@ -1 +1 @@
-Subproject commit d0dc6c97a6486f68bac782fff135086eae6d77ec
+Subproject commit e269950a57fa6fcda356426545fb5aa3691a7ced
index ef6eee75f1ce6c2cdc4d0ed83e43144e60bb68de..d4d26654ed114fa7cb3bc3ff3302500838d54ccf 100644 (file)
@@ -434,6 +434,9 @@ replacement is purely textual, with no consideration of the current system's
 pathname syntax. For example `--remap-path-prefix foo=bar` will match
 `foo/lib.rs` but not `./foo/lib.rs`.
 
+When multiple remappings are given and several of them match, the **last**
+matching one is applied.
+
 <a id="option-json"></a>
 ## `--json`: configure json messages printed by the compiler
 
index b33405f18e90bcc2c92672cdaecfdc0df869a78b..9bbf9e28fffe2bdec384da186e4f2b1eec2f417b 100644 (file)
@@ -14,6 +14,9 @@ This feature allows for use of one of following sanitizers:
   forward-edge control flow protection.
 * [HWAddressSanitizer](#hwaddresssanitizer) a memory error detector similar to
   AddressSanitizer, but based on partial hardware assistance.
+* [KernelControlFlowIntegrity](#kernelcontrolflowintegrity) LLVM Kernel Control
+  Flow Integrity (KCFI) provides forward-edge control flow protection for
+  operating systems kernels.
 * [LeakSanitizer](#leaksanitizer) a run-time memory leak detector.
 * [MemorySanitizer](#memorysanitizer) a detector of uninitialized reads.
 * [MemTagSanitizer](#memtagsanitizer) fast memory error detector based on
@@ -502,6 +505,32 @@ Registers where the failure occurred (pc 0xaaaae0ae4a98):
 SUMMARY: HWAddressSanitizer: tag-mismatch (/.../main+0x54a94)
 ```
 
+# KernelControlFlowIntegrity
+
+The LLVM Kernel Control Flow Integrity (CFI) support to the Rust compiler
+initially provides forward-edge control flow protection for operating systems
+kernels for Rust-compiled code only by aggregating function pointers in groups
+identified by their return and parameter types. (See [LLVM commit cff5bef "KCFI
+sanitizer"](https://github.com/llvm/llvm-project/commit/cff5bef948c91e4919de8a5fb9765e0edc13f3de).)
+
+Forward-edge control flow protection for C or C++ and Rust -compiled code "mixed
+binaries" (i.e., for when C or C++ and Rust -compiled code share the same
+virtual address space) will be provided in later work by defining and using
+compatible type identifiers (see Type metadata in the design document in the
+tracking issue [#89653](https://github.com/rust-lang/rust/issues/89653)).
+
+LLVM KCFI can be enabled with `-Zsanitizer=kcfi`.
+
+LLVM KCFI is supported on the following targets:
+
+* `aarch64-linux-android`
+* `aarch64-unknown-linux-gnu`
+* `x86_64-linux-android`
+* `x86_64-unknown-linux-gnu`
+
+See the [Clang KernelControlFlowIntegrity documentation][clang-kcfi] for more
+details.
+
 # LeakSanitizer
 
 LeakSanitizer is run-time memory leak detector.
@@ -693,6 +722,7 @@ Sanitizers produce symbolized stacktraces when llvm-symbolizer binary is in `PAT
 [clang-asan]: https://clang.llvm.org/docs/AddressSanitizer.html
 [clang-cfi]: https://clang.llvm.org/docs/ControlFlowIntegrity.html
 [clang-hwasan]: https://clang.llvm.org/docs/HardwareAssistedAddressSanitizerDesign.html
+[clang-kcfi]: https://clang.llvm.org/docs/ControlFlowIntegrity.html#fsanitize-kcfi
 [clang-lsan]: https://clang.llvm.org/docs/LeakSanitizer.html
 [clang-msan]: https://clang.llvm.org/docs/MemorySanitizer.html
 [clang-scs]: https://clang.llvm.org/docs/ShadowCallStack.html
index 11ef0cfdb142262385678aa0f093af66e2c375bb..b492da88474ee297d63fa6fbafc08fbd9c1f8ae5 100644 (file)
@@ -12,7 +12,7 @@ Specification].
 
 Example:
 
-```rust
+```rust,ignore (not-all-targets-support-uefi)
 #![feature(abi_efiapi)]
 
 extern "efiapi" { fn f1(); }
index 1e7b4fe15b68cad5c59d74e96df437a4d4cf57d9..0271c27b4f522142474fb7ef9e910b7684093d02 100644 (file)
@@ -32,7 +32,7 @@ features = ["fmt", "env-filter", "smallvec", "parking_lot", "ansi"]
 rayon = "1.5.1"
 
 [dev-dependencies]
-expect-test = "1.0"
+expect-test = "1.4.0"
 
 [features]
 jemalloc = []
index b18788a033fb68e6625ed00779c23f7feb591749..2a2a9470d25c0ee4da19badf253f0207a6dcdda7 100644 (file)
@@ -12,7 +12,7 @@
 
 use rustc_ast as ast;
 use rustc_attr as attr;
-use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet};
+use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet, IndexEntry};
 use rustc_hir as hir;
 use rustc_hir::def::{CtorKind, DefKind, Res};
 use rustc_hir::def_id::{DefId, LOCAL_CRATE};
@@ -598,47 +598,105 @@ pub(crate) fn clean_generics<'tcx>(
         })
         .collect::<Vec<_>>();
 
+    let mut bound_predicates = FxIndexMap::default();
+    let mut region_predicates = FxIndexMap::default();
+    let mut eq_predicates = ThinVec::default();
+    for pred in gens.predicates.iter().filter_map(|x| clean_where_predicate(x, cx)) {
+        match pred {
+            WherePredicate::BoundPredicate { ty, bounds, bound_params } => {
+                match bound_predicates.entry(ty) {
+                    IndexEntry::Vacant(v) => {
+                        v.insert((bounds, bound_params));
+                    }
+                    IndexEntry::Occupied(mut o) => {
+                        // we merge both bounds.
+                        for bound in bounds {
+                            if !o.get().0.contains(&bound) {
+                                o.get_mut().0.push(bound);
+                            }
+                        }
+                        for bound_param in bound_params {
+                            if !o.get().1.contains(&bound_param) {
+                                o.get_mut().1.push(bound_param);
+                            }
+                        }
+                    }
+                }
+            }
+            WherePredicate::RegionPredicate { lifetime, bounds } => {
+                match region_predicates.entry(lifetime) {
+                    IndexEntry::Vacant(v) => {
+                        v.insert(bounds);
+                    }
+                    IndexEntry::Occupied(mut o) => {
+                        // we merge both bounds.
+                        for bound in bounds {
+                            if !o.get().contains(&bound) {
+                                o.get_mut().push(bound);
+                            }
+                        }
+                    }
+                }
+            }
+            WherePredicate::EqPredicate { lhs, rhs, bound_params } => {
+                eq_predicates.push(WherePredicate::EqPredicate { lhs, rhs, bound_params });
+            }
+        }
+    }
+
     let mut params = ThinVec::with_capacity(gens.params.len());
+    // In this loop, we gather the generic parameters (`<'a, B: 'a>`) and check if they have
+    // bounds in the where predicates. If so, we move their bounds into the where predicates
+    // while also preventing duplicates.
     for p in gens.params.iter().filter(|p| !is_impl_trait(p) && !is_elided_lifetime(p)) {
-        let p = clean_generic_param(cx, Some(gens), p);
+        let mut p = clean_generic_param(cx, Some(gens), p);
+        match &mut p.kind {
+            GenericParamDefKind::Lifetime { ref mut outlives } => {
+                if let Some(region_pred) = region_predicates.get_mut(&Lifetime(p.name)) {
+                    // We merge bounds in the `where` clause.
+                    for outlive in outlives.drain(..) {
+                        let outlive = GenericBound::Outlives(outlive);
+                        if !region_pred.contains(&outlive) {
+                            region_pred.push(outlive);
+                        }
+                    }
+                }
+            }
+            GenericParamDefKind::Type { bounds, synthetic: false, .. } => {
+                if let Some(bound_pred) = bound_predicates.get_mut(&Type::Generic(p.name)) {
+                    // We merge bounds in the `where` clause.
+                    for bound in bounds.drain(..) {
+                        if !bound_pred.0.contains(&bound) {
+                            bound_pred.0.push(bound);
+                        }
+                    }
+                }
+            }
+            GenericParamDefKind::Type { .. } | GenericParamDefKind::Const { .. } => {
+                // nothing to do here.
+            }
+        }
         params.push(p);
     }
     params.extend(impl_trait_params);
 
-    let mut generics = Generics {
+    Generics {
         params,
-        where_predicates: gens
-            .predicates
-            .iter()
-            .filter_map(|x| clean_where_predicate(x, cx))
+        where_predicates: bound_predicates
+            .into_iter()
+            .map(|(ty, (bounds, bound_params))| WherePredicate::BoundPredicate {
+                ty,
+                bounds,
+                bound_params,
+            })
+            .chain(
+                region_predicates
+                    .into_iter()
+                    .map(|(lifetime, bounds)| WherePredicate::RegionPredicate { lifetime, bounds }),
+            )
+            .chain(eq_predicates.into_iter())
             .collect(),
-    };
-
-    // Some duplicates are generated for ?Sized bounds between type params and where
-    // predicates. The point in here is to move the bounds definitions from type params
-    // to where predicates when such cases occur.
-    for where_pred in &mut generics.where_predicates {
-        match *where_pred {
-            WherePredicate::BoundPredicate { ty: Generic(ref name), ref mut bounds, .. } => {
-                if bounds.is_empty() {
-                    for param in &mut generics.params {
-                        match param.kind {
-                            GenericParamDefKind::Lifetime { .. } => {}
-                            GenericParamDefKind::Type { bounds: ref mut ty_bounds, .. } => {
-                                if &param.name == name {
-                                    mem::swap(bounds, ty_bounds);
-                                    break;
-                                }
-                            }
-                            GenericParamDefKind::Const { .. } => {}
-                        }
-                    }
-                }
-            }
-            _ => continue,
-        }
     }
-    generics
 }
 
 fn clean_ty_generics<'tcx>(
@@ -2231,6 +2289,26 @@ fn clean_extern_crate<'tcx>(
 }
 
 fn clean_use_statement<'tcx>(
+    import: &hir::Item<'tcx>,
+    name: Symbol,
+    path: &hir::UsePath<'tcx>,
+    kind: hir::UseKind,
+    cx: &mut DocContext<'tcx>,
+    inlined_names: &mut FxHashSet<(ItemType, Symbol)>,
+) -> Vec<Item> {
+    let mut items = Vec::new();
+    let hir::UsePath { segments, ref res, span } = *path;
+    for &res in res {
+        if let Res::Def(DefKind::Ctor(..), _) | Res::SelfCtor(..) = res {
+            continue;
+        }
+        let path = hir::Path { segments, res, span };
+        items.append(&mut clean_use_statement_inner(import, name, &path, kind, cx, inlined_names));
+    }
+    items
+}
+
+fn clean_use_statement_inner<'tcx>(
     import: &hir::Item<'tcx>,
     name: Symbol,
     path: &hir::Path<'tcx>,
index 8c3b289d34628e4b354adedb535b2aa557e38162..98329e7fc91935d61601a784ced2f4773fd4c866 100644 (file)
@@ -240,7 +240,9 @@ pub(crate) fn keywords(&self, tcx: TyCtxt<'_>) -> ThinVec<(DefId, Symbol)> {
                         hir::ItemKind::Use(path, hir::UseKind::Single)
                             if tcx.visibility(id.owner_id).is_public() =>
                         {
-                            as_keyword(path.res.expect_non_local())
+                            path.res
+                                .iter()
+                                .find_map(|res| as_keyword(res.expect_non_local()))
                                 .map(|(_, prim)| (id.owner_id.to_def_id(), prim))
                         }
                         _ => None,
@@ -308,10 +310,11 @@ pub(crate) fn primitives(&self, tcx: TyCtxt<'_>) -> ThinVec<(DefId, PrimitiveTyp
                         hir::ItemKind::Use(path, hir::UseKind::Single)
                             if tcx.visibility(id.owner_id).is_public() =>
                         {
-                            as_primitive(path.res.expect_non_local()).map(|(_, prim)| {
+                            path.res
+                                .iter()
+                                .find_map(|res| as_primitive(res.expect_non_local()))
                                 // Pretend the primitive is local.
-                                (id.owner_id.to_def_id(), prim)
-                            })
+                                .map(|(_, prim)| (id.owner_id.to_def_id(), prim))
                         }
                         _ => None,
                     }
index e0cdb86d9d1dc152e47f97f85e5ea4456ed0f2ea..56b40d8c66baffa627ab03e1a9b83788b73d276d 100644 (file)
@@ -69,6 +69,8 @@ pub(crate) struct Options {
     pub(crate) input: PathBuf,
     /// The name of the crate being documented.
     pub(crate) crate_name: Option<String>,
+    /// Whether or not this is a bin crate
+    pub(crate) bin_crate: bool,
     /// Whether or not this is a proc-macro crate
     pub(crate) proc_macro_crate: bool,
     /// How to format errors and warnings.
@@ -176,6 +178,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         f.debug_struct("Options")
             .field("input", &self.input)
             .field("crate_name", &self.crate_name)
+            .field("bin_crate", &self.bin_crate)
             .field("proc_macro_crate", &self.proc_macro_crate)
             .field("error_format", &self.error_format)
             .field("libs", &self.libs)
@@ -667,6 +670,7 @@ fn println_condition(condition: Condition) {
             None => OutputFormat::default(),
         };
         let crate_name = matches.opt_str("crate-name");
+        let bin_crate = crate_types.contains(&CrateType::Executable);
         let proc_macro_crate = crate_types.contains(&CrateType::ProcMacro);
         let playground_url = matches.opt_str("playground-url");
         let maybe_sysroot = matches.opt_str("sysroot").map(PathBuf::from);
@@ -718,6 +722,7 @@ fn println_condition(condition: Condition) {
             rustc_feature::UnstableFeatures::from_environment(crate_name.as_deref());
         let options = Options {
             input,
+            bin_crate,
             proc_macro_crate,
             error_format,
             diagnostic_width,
index 893249e88cf7b658b7b4e0b6d020c45ae99d0817..da0df596c41e34f7ca88e07b1e7b0811b75ed22d 100644 (file)
@@ -489,7 +489,7 @@ fn nested_visit_map(&mut self) -> Self::Map {
         self.tcx.hir()
     }
 
-    fn visit_path(&mut self, path: &'tcx Path<'_>, _id: HirId) {
+    fn visit_path(&mut self, path: &Path<'tcx>, _id: HirId) {
         debug!("visiting path {:?}", path);
         if path.res == Res::Err {
             // We have less context here than in rustc_resolve,
index cd8c8c463b1ab60bafcaf15168de9dc1d6003362..8a9e6caf611bad111308874cd8bd3d7685cb130d 100644 (file)
 use super::format::{self, Buffer};
 
 /// This type is needed in case we want to render links on items to allow to go to their definition.
-pub(crate) struct HrefContext<'a, 'b, 'c> {
-    pub(crate) context: &'a Context<'b>,
+pub(crate) struct HrefContext<'a, 'tcx> {
+    pub(crate) context: &'a Context<'tcx>,
     /// This span contains the current file we're going through.
     pub(crate) file_span: Span,
     /// This field is used to know "how far" from the top of the directory we are to link to either
     /// documentation pages or other source pages.
-    pub(crate) root_path: &'c str,
+    pub(crate) root_path: &'a str,
     /// This field is used to calculate precise local URLs.
-    pub(crate) current_href: &'c str,
+    pub(crate) current_href: String,
 }
 
 /// Decorations are represented as a map from CSS class to vector of character ranges.
@@ -70,7 +70,7 @@ pub(crate) fn render_source_with_highlighting(
     src: &str,
     out: &mut Buffer,
     line_numbers: Buffer,
-    href_context: HrefContext<'_, '_, '_>,
+    href_context: HrefContext<'_, '_>,
     decoration_info: DecorationInfo,
     extra: Option<&str>,
 ) {
@@ -137,7 +137,7 @@ fn can_merge(class1: Option<Class>, class2: Option<Class>, text: &str) -> bool {
 
 /// This type is used as a conveniency to prevent having to pass all its fields as arguments into
 /// the various functions (which became its methods).
-struct TokenHandler<'a, 'b, 'c, 'd, 'e> {
+struct TokenHandler<'a, 'tcx> {
     out: &'a mut Buffer,
     /// It contains the closing tag and the associated `Class`.
     closing_tags: Vec<(&'static str, Class)>,
@@ -149,11 +149,11 @@ struct TokenHandler<'a, 'b, 'c, 'd, 'e> {
     current_class: Option<Class>,
     /// We need to keep the `Class` for each element because it could contain a `Span` which is
     /// used to generate links.
-    pending_elems: Vec<(&'b str, Option<Class>)>,
-    href_context: Option<HrefContext<'c, 'd, 'e>>,
+    pending_elems: Vec<(&'a str, Option<Class>)>,
+    href_context: Option<HrefContext<'a, 'tcx>>,
 }
 
-impl<'a, 'b, 'c, 'd, 'e> TokenHandler<'a, 'b, 'c, 'd, 'e> {
+impl<'a, 'tcx> TokenHandler<'a, 'tcx> {
     fn handle_exit_span(&mut self) {
         // We can't get the last `closing_tags` element using `pop()` because `closing_tags` is
         // being used in `write_pending_elems`.
@@ -205,7 +205,7 @@ fn write_pending_elems(&mut self, current_class: Option<Class>) -> bool {
     }
 }
 
-impl<'a, 'b, 'c, 'd, 'e> Drop for TokenHandler<'a, 'b, 'c, 'd, 'e> {
+impl<'a, 'tcx> Drop for TokenHandler<'a, 'tcx> {
     /// When leaving, we need to flush all pending data to not have missing content.
     fn drop(&mut self) {
         if self.pending_exit_span.is_some() {
@@ -230,7 +230,7 @@ fn drop(&mut self) {
 fn write_code(
     out: &mut Buffer,
     src: &str,
-    href_context: Option<HrefContext<'_, '_, '_>>,
+    href_context: Option<HrefContext<'_, '_>>,
     decoration_info: Option<DecorationInfo>,
 ) {
     // This replace allows to fix how the code source with DOS backline characters is displayed.
@@ -514,18 +514,18 @@ fn new(info: DecorationInfo) -> Self {
 
 /// Processes program tokens, classifying strings of text by highlighting
 /// category (`Class`).
-struct Classifier<'a> {
-    tokens: PeekIter<'a>,
+struct Classifier<'src> {
+    tokens: PeekIter<'src>,
     in_attribute: bool,
     in_macro: bool,
     in_macro_nonterminal: bool,
     byte_pos: u32,
     file_span: Span,
-    src: &'a str,
+    src: &'src str,
     decorations: Option<Decorations>,
 }
 
-impl<'a> Classifier<'a> {
+impl<'src> Classifier<'src> {
     /// Takes as argument the source code to HTML-ify, the rust edition to use and the source code
     /// file span which will be used later on by the `span_correspondance_map`.
     fn new(src: &str, file_span: Span, decoration_info: Option<DecorationInfo>) -> Classifier<'_> {
@@ -603,7 +603,7 @@ fn get_full_ident_path(&mut self) -> Vec<(TokenKind, usize, usize)> {
     ///
     /// It returns the token's kind, the token as a string and its byte position in the source
     /// string.
-    fn next(&mut self) -> Option<(TokenKind, &'a str, u32)> {
+    fn next(&mut self) -> Option<(TokenKind, &'src str, u32)> {
         if let Some((kind, text)) = self.tokens.next() {
             let before = self.byte_pos;
             self.byte_pos += text.len() as u32;
@@ -618,7 +618,7 @@ fn next(&mut self) -> Option<(TokenKind, &'a str, u32)> {
     /// The general structure for this method is to iterate over each token,
     /// possibly giving it an HTML span with a class specifying what flavor of
     /// token is used.
-    fn highlight(mut self, sink: &mut dyn FnMut(Highlight<'a>)) {
+    fn highlight(mut self, sink: &mut dyn FnMut(Highlight<'src>)) {
         loop {
             if let Some(decs) = self.decorations.as_mut() {
                 let byte_pos = self.byte_pos;
@@ -666,8 +666,8 @@ fn highlight(mut self, sink: &mut dyn FnMut(Highlight<'a>)) {
     fn advance(
         &mut self,
         token: TokenKind,
-        text: &'a str,
-        sink: &mut dyn FnMut(Highlight<'a>),
+        text: &'src str,
+        sink: &mut dyn FnMut(Highlight<'src>),
         before: u32,
     ) {
         let lookahead = self.peek();
@@ -881,7 +881,7 @@ fn check_if_is_union_keyword(&mut self) -> bool {
 fn enter_span(
     out: &mut Buffer,
     klass: Class,
-    href_context: &Option<HrefContext<'_, '_, '_>>,
+    href_context: &Option<HrefContext<'_, '_>>,
 ) -> &'static str {
     string_without_closing_tag(out, "", Some(klass), href_context, true).expect(
         "internal error: enter_span was called with Some(klass) but did not return a \
@@ -914,7 +914,7 @@ fn string<T: Display>(
     out: &mut Buffer,
     text: T,
     klass: Option<Class>,
-    href_context: &Option<HrefContext<'_, '_, '_>>,
+    href_context: &Option<HrefContext<'_, '_>>,
     open_tag: bool,
 ) {
     if let Some(closing_tag) = string_without_closing_tag(out, text, klass, href_context, open_tag)
@@ -936,7 +936,7 @@ fn string_without_closing_tag<T: Display>(
     out: &mut Buffer,
     text: T,
     klass: Option<Class>,
-    href_context: &Option<HrefContext<'_, '_, '_>>,
+    href_context: &Option<HrefContext<'_, '_>>,
     open_tag: bool,
 ) -> Option<&'static str> {
     let Some(klass) = klass
@@ -985,7 +985,7 @@ fn string_without_closing_tag<T: Display>(
                 // https://github.com/rust-lang/rust/blob/60f1a2fc4b535ead9c85ce085fdce49b1b097531/src/librustdoc/html/render/context.rs#L315-L338
                 match href {
                     LinkFromSrc::Local(span) => {
-                        context.href_from_span_relative(*span, href_context.current_href)
+                        context.href_from_span_relative(*span, &href_context.current_href)
                     }
                     LinkFromSrc::External(def_id) => {
                         format::href_with_root_path(*def_id, context, Some(href_context.root_path))
index 5ce62224d35e54130d87c5c1fcac24162c2578d9..1e1c657b0bf22f7d71306f57099be4ac8d9c3145 100644 (file)
@@ -246,8 +246,6 @@ fn next(&mut self) -> Option<Self::Item> {
                 _ => {}
             }
         }
-        let lines = origtext.lines().filter_map(|l| map_line(l).for_html());
-        let text = lines.intersperse("\n".into()).collect::<String>();
 
         let parse_result = match kind {
             CodeBlockKind::Fenced(ref lang) => {
@@ -260,7 +258,7 @@ fn next(&mut self) -> Option<Self::Item> {
                                  <pre class=\"language-{}\"><code>{}</code></pre>\
                              </div>",
                             lang,
-                            Escape(&text),
+                            Escape(&origtext),
                         )
                         .into(),
                     ));
@@ -270,6 +268,9 @@ fn next(&mut self) -> Option<Self::Item> {
             CodeBlockKind::Indented => Default::default(),
         };
 
+        let lines = origtext.lines().filter_map(|l| map_line(l).for_html());
+        let text = lines.intersperse("\n".into()).collect::<String>();
+
         compile_fail = parse_result.compile_fail;
         should_panic = parse_result.should_panic;
         ignore = parse_result.ignore;
index e4f72a057892f5ee1098859fecc557aae49df72a..5878c58264ec361f7c008a1165a6e43d9f0bae2e 100644 (file)
@@ -309,3 +309,48 @@ fn add_test(&mut self, _test: String, _config: LangString, line: usize) {
     t("```rust\n```\n```rust\n```", &[1, 3]);
     t("```rust\n```\n ```rust\n```", &[1, 3]);
 }
+
+#[test]
+fn test_ascii_with_prepending_hashtag() {
+    fn t(input: &str, expect: &str) {
+        let mut map = IdMap::new();
+        let output = Markdown {
+            content: input,
+            links: &[],
+            ids: &mut map,
+            error_codes: ErrorCodes::Yes,
+            edition: DEFAULT_EDITION,
+            playground: &None,
+            heading_offset: HeadingOffset::H2,
+        }
+        .into_string();
+        assert_eq!(output, expect, "original: {}", input);
+    }
+
+    t(
+        r#"```ascii
+#..#.####.#....#.....##..
+#..#.#....#....#....#..#.
+####.###..#....#....#..#.
+#..#.#....#....#....#..#.
+#..#.#....#....#....#..#.
+#..#.####.####.####..##..
+```"#,
+        "<div class=\"example-wrap\"><pre class=\"language-ascii\"><code>\
+#..#.####.#....#.....##..
+#..#.#....#....#....#..#.
+####.###..#....#....#..#.
+#..#.#....#....#....#..#.
+#..#.#....#....#....#..#.
+#..#.####.####.####..##..
+</code></pre></div>",
+    );
+    t(
+        r#"```markdown
+# hello
+```"#,
+        "<div class=\"example-wrap\"><pre class=\"language-markdown\"><code>\
+# hello
+</code></pre></div>",
+    );
+}
index 08f8096b07bd66399ac9bda4b17f6f19d8fa56c7..36d15ec3b8640cde9642b080ffe1db218dc848a7 100644 (file)
@@ -2957,14 +2957,23 @@ fn render_call_locations(w: &mut Buffer, cx: &mut Context<'_>, item: &clean::Ite
 
     // The call locations are output in sequence, so that sequence needs to be determined.
     // Ideally the most "relevant" examples would be shown first, but there's no general algorithm
-    // for determining relevance. Instead, we prefer the smallest examples being likely the easiest to
-    // understand at a glance.
+    // for determining relevance. We instead proxy relevance with the following heuristics:
+    //   1. Code written to be an example is better than code not written to be an example, e.g.
+    //      a snippet from examples/foo.rs is better than src/lib.rs. We don't know the Cargo
+    //      directory structure in Rustdoc, so we proxy this by prioritizing code that comes from
+    //      a --crate-type bin.
+    //   2. Smaller examples are better than large examples. So we prioritize snippets that have
+    //      the smallest number of lines in their enclosing item.
+    //   3. Finally we sort by the displayed file name, which is arbitrary but prevents the
+    //      ordering of examples from randomly changing between Rustdoc invocations.
     let ordered_locations = {
-        let sort_criterion = |(_, call_data): &(_, &CallData)| {
+        fn sort_criterion<'a>(
+            (_, call_data): &(&PathBuf, &'a CallData),
+        ) -> (bool, u32, &'a String) {
             // Use the first location because that's what the user will see initially
             let (lo, hi) = call_data.locations[0].enclosing_item.byte_span;
-            hi - lo
-        };
+            (!call_data.is_bin, hi - lo, &call_data.display_name)
+        }
 
         let mut locs = call_locations.iter().collect::<Vec<_>>();
         locs.sort_by_key(sort_criterion);
index 151ec2b28adc9860b47e71fbb48edd0f69d399a7..4514894cabe0fcdf33035cf0b9b2b3ed580946ff 100644 (file)
@@ -140,7 +140,7 @@ fn nested_visit_map(&mut self) -> Self::Map {
         self.tcx.hir()
     }
 
-    fn visit_path(&mut self, path: &'tcx rustc_hir::Path<'tcx>, _id: HirId) {
+    fn visit_path(&mut self, path: &rustc_hir::Path<'tcx>, _id: HirId) {
         if self.handle_macro(path.span) {
             return;
         }
@@ -190,12 +190,4 @@ fn visit_expr(&mut self, expr: &'tcx rustc_hir::Expr<'tcx>) {
         }
         intravisit::walk_expr(self, expr);
     }
-
-    fn visit_use(&mut self, path: &'tcx rustc_hir::Path<'tcx>, id: HirId) {
-        if self.handle_macro(path.span) {
-            return;
-        }
-        self.handle_path(path);
-        intravisit::walk_use(self, path, id);
-    }
 }
index 54e296959b0ec97fb569a2210d1e0054cece775f..e639fadeb96733ddb5848e6ef9c677614eaaa5b0 100644 (file)
@@ -276,7 +276,7 @@ pub(crate) fn print_src(
     let mut line_numbers = Buffer::empty_from(buf);
     let extra;
     line_numbers.write_str("<pre class=\"src-line-numbers\">");
-    let current_href = &context
+    let current_href = context
         .href_from_span(clean::Span::new(file_span), false)
         .expect("only local crates should have sources emitted");
     match source_context {
index 7e41d80f5460f499f60e1a823757ac4c1eb38e38..91162ca4892ca0a43caa71b64d54696bee1a69a7 100644 (file)
@@ -195,11 +195,8 @@ h1, h2, h3, h4, h5, h6,
 span.since,
 a.srclink,
 #help-button > a,
-details.rustdoc-toggle.top-doc > summary,
-details.rustdoc-toggle.non-exhaustive > summary,
-.scraped-example-title,
-.more-examples-toggle summary, .more-examples-toggle .hide-more,
-.example-links a,
+summary.hideme,
+.scraped-example-list,
 /* This selector is for the items listed in the "all items" page. */
 ul.all-items {
        font-family: "Fira Sans", Arial, NanumBarunGothic, sans-serif;
@@ -215,8 +212,7 @@ pre.rust a,
 .mobile-topbar h2 a,
 h1 a,
 .search-results a,
-.module-item .stab,
-.import-item .stab,
+.stab,
 .result-name .primitive > i, .result-name .keyword > i {
        color: var(--main-color);
 }
@@ -634,22 +630,16 @@ pre, .rustdoc.source .example-wrap {
 
 .docblock table {
        margin: .5em 0;
-       width: calc(100% - 2px);
-       overflow-x: auto;
-       display: block;
        border-collapse: collapse;
 }
 
-.docblock table td {
+.docblock table td, .docblock table th {
        padding: .5em;
-       border: 1px dashed var(--border-color);
-       vertical-align: top;
+       border: 1px solid var(--border-color);
 }
 
-.docblock table th {
-       padding: .5em;
-       text-align: left;
-       border: 1px solid var(--border-color);
+.docblock table tbody tr:nth-child(2n) {
+       background: var(--table-alt-row-background-color);
 }
 
 /* Shift "where ..." part of method or fn definition down a line */
@@ -910,6 +900,7 @@ so that we can apply CSS-filters to change the arrow color in themes */
 
 .popover {
        position: absolute;
+       top: 100%;
        right: 0;
        z-index: 2;
        display: block;
@@ -969,22 +960,29 @@ so that we can apply CSS-filters to change the arrow color in themes */
 }
 
 .item-info .stab {
-       width: fit-content;
        /* This min-height is needed to unify the height of the stab elements because some of them
           have emojis.
        */
        min-height: 36px;
        display: flex;
-       align-items: center;
-       white-space: pre-wrap;
-}
-.stab {
        padding: 3px;
        margin-bottom: 5px;
+}
+.item-left .stab {
+       margin-left: 0.3125em;
+}
+.stab {
+       padding: 0 2px;
        font-size: 0.875rem;
        font-weight: normal;
        color: var(--main-color);
        background-color: var(--stab-background-color);
+       width: fit-content;
+       align-items: center;
+       white-space: pre-wrap;
+       border-radius: 3px;
+       display: inline-flex;
+       vertical-align: text-bottom;
 }
 
 .stab.portability > code {
@@ -997,12 +995,6 @@ so that we can apply CSS-filters to change the arrow color in themes */
        margin-right: 0.3rem;
 }
 
-/* This is to prevent the `.stab` elements to overflow the .docblock elements. */
-.docblock .stab {
-       padding: 0 0.125em;
-       margin-bottom: 0;
-}
-
 /* Black one-pixel outline around emoji shapes */
 .emoji {
        text-shadow:
@@ -1012,18 +1004,6 @@ so that we can apply CSS-filters to change the arrow color in themes */
                0 -1px 0 black;
 }
 
-.module-item .stab,
-.import-item .stab {
-       border-radius: 3px;
-       display: inline-block;
-       font-size: 0.875rem;
-       line-height: 1.2;
-       margin-bottom: 0;
-       margin-left: 0.3125em;
-       padding: 2px;
-       vertical-align: text-bottom;
-}
-
 .module-item.unstable,
 .import-item.unstable {
        opacity: 0.65;
@@ -1359,22 +1339,24 @@ a.test-arrow:hover {
 }
 #settings-menu, #help-button {
        margin-left: 4px;
-       outline: none;
+       display: flex;
 }
 
 #settings-menu > a, #help-button > a, #copy-path {
        width: 33px;
-       line-height: 1.5;
 }
 
 #settings-menu > a, #help-button > a {
-       padding: 5px;
-       height: 100%;
-       display: block;
+       display: flex;
+       align-items: center;
+       justify-content: center;
        background-color: var(--button-background-color);
        border: 1px solid var(--border-color);
        border-radius: 2px;
        color: var(--settings-button-color);
+       /* Rare exception to specifying font sizes in rem. Since this is acting
+          as an icon, it's okay to specify their sizes in pixels. */
+       font-size: 20px;
 }
 
 #settings-menu > a:hover, #settings-menu > a:focus,
@@ -1410,14 +1392,6 @@ a.test-arrow:hover {
        animation: rotating 2s linear infinite;
 }
 
-#help-button > a {
-       text-align: center;
-       /* Rare exception to specifying font sizes in rem. Since this is acting
-          as an icon, it's okay to specify their sizes in pixels. */
-       font-size: 20px;
-       padding-top: 2px;
-}
-
 kbd {
        display: inline-block;
        padding: 3px 5px;
@@ -1491,6 +1465,7 @@ details.rustdoc-toggle {
        "Expand description" or "Show methods". */
 details.rustdoc-toggle > summary.hideme {
        cursor: pointer;
+       font-size: 1rem;
 }
 
 details.rustdoc-toggle > summary {
@@ -1516,6 +1491,7 @@ details.rustdoc-toggle > summary::before {
        display: inline-block;
        vertical-align: middle;
        opacity: .5;
+       filter: var(--toggle-filter);
 }
 
 details.rustdoc-toggle > summary.hideme > span,
@@ -1552,13 +1528,6 @@ details.rustdoc-toggle > summary:focus-visible::before {
        outline-offset: 1px;
 }
 
-details.rustdoc-toggle.top-doc > summary,
-details.rustdoc-toggle.top-doc > summary::before,
-details.rustdoc-toggle.non-exhaustive > summary,
-details.rustdoc-toggle.non-exhaustive > summary::before {
-       font-size: 1rem;
-}
-
 details.non-exhaustive {
        margin-bottom: 8px;
 }
@@ -1591,17 +1560,11 @@ details.rustdoc-toggle[open] > summary.hideme > span {
        display: none;
 }
 
-details.rustdoc-toggle[open] > summary::before,
-details.rustdoc-toggle[open] > summary.hideme::before {
+details.rustdoc-toggle[open] > summary::before {
        background: url("toggle-minus-31bbd6e4c77f5c96.svg") no-repeat top left;
-       width: 16px;
-       height: 16px;
-       display: inline-block;
-       content: "";
 }
 
-details.rustdoc-toggle[open] > summary::after,
-details.rustdoc-toggle[open] > summary.hideme::after {
+details.rustdoc-toggle[open] > summary::after {
        content: "Collapse";
 }
 
@@ -1659,10 +1622,6 @@ in storage.js
                content: "Since ";
        }
 
-       #copy-path {
-               display: none;
-       }
-
        /* Hide the logo and item name from the sidebar. Those are displayed
           in the mobile-topbar instead. */
        .sidebar .sidebar-logo,
@@ -1676,8 +1635,6 @@ in storage.js
                /* Hide the sidebar offscreen while not in use. Doing this instead of display: none means
                   the sidebar stays visible for screen readers, which is useful for navigation. */
                left: -1000px;
-               margin: 0;
-               padding: 0;
                z-index: 11;
                /* Reduce height slightly to account for mobile topbar. */
                height: calc(100vh - 45px);
@@ -1776,7 +1733,6 @@ in storage.js
                top: 100px;
                width: 30px;
                font-size: 1.5rem;
-               text-align: center;
                padding: 0;
                z-index: 10;
                border-top-right-radius: 3px;
@@ -1796,8 +1752,8 @@ in storage.js
                border-bottom: 1px solid;
        }
 
-       /* We don't display the help button on mobile devices. */
-       #help-button {
+       /* We don't display these buttons on mobile devices. */
+       #copy-path, #help-button {
                display: none;
        }
 
@@ -1841,6 +1797,22 @@ in storage.js
        }
 }
 
+/* Should have min-width: (N + 1)px where N is the mobile breakpoint above. */
+@media (min-width: 701px) {
+       /* Places file-link for a scraped example on top of the example to save space.
+          We only do this on large screens so the file-link doesn't overlap too much
+                with the example's content. */
+       .scraped-example-title {
+               position: absolute;
+               z-index: 10;
+               background: var(--main-background-color);
+               bottom: 8px;
+               right: 5px;
+               padding: 2px 4px;
+               box-shadow: 0 0 4px var(--main-background-color);
+       }
+}
+
 @media print {
        nav.sidebar, nav.sub, .out-of-band, a.srclink, #copy-path,
        details.rustdoc-toggle[open] > summary::before, details.rustdoc-toggle > summary::before,
@@ -1927,6 +1899,11 @@ in storage.js
        border-radius: 50px;
 }
 
+.scraped-example {
+       /* So .scraped-example-title can be positioned absolutely */
+       position: relative;
+}
+
 .scraped-example .code-wrapper {
        position: relative;
        display: flex;
@@ -1936,18 +1913,30 @@ in storage.js
 }
 
 .scraped-example:not(.expanded) .code-wrapper {
-       max-height: 240px;
+       /* scrape-examples.js has a constant DEFAULT_MAX_LINES (call it N) for the number
+        * of lines shown in the un-expanded example code viewer. This pre needs to have
+        * a max-height equal to line-height * N. The line-height is currently 1.5em,
+        * and we include additional 10px for padding. */
+        max-height: calc(1.5em * 5 + 10px);
 }
 
 .scraped-example:not(.expanded) .code-wrapper pre {
        overflow-y: hidden;
-       max-height: 240px;
        padding-bottom: 0;
+       /* See above comment, should be the same max-height. */
+       max-height: calc(1.5em * 5 + 10px);
+}
+
+.more-scraped-examples .scraped-example:not(.expanded) .code-wrapper,
+.more-scraped-examples .scraped-example:not(.expanded) .code-wrapper pre {
+       /* See above comment, except this height is based on HIDDEN_MAX_LINES. */
+       max-height: calc(1.5em * 10 + 10px);
 }
 
 .scraped-example .code-wrapper .next,
 .scraped-example .code-wrapper .prev,
 .scraped-example .code-wrapper .expand {
+       color: var(--main-color);
        position: absolute;
        top: 0.25em;
        z-index: 1;
@@ -1994,7 +1983,9 @@ in storage.js
 }
 
 .scraped-example .code-wrapper .example-wrap {
-       flex: 1;
+       display: grid;
+       grid-template-columns: max-content auto;
+       width: 100%;
        overflow-x: auto;
        overflow-y: hidden;
        margin-bottom: 0;
index de7db7d438c9f4baf2ee19965d6202b62c65f640..eba845bf5a91565f2219f56f71c9eeb8701526a2 100644 (file)
@@ -21,6 +21,7 @@ Original by Dempfi (https://github.com/dempfi/ayu)
        --right-side-color: grey;
        --code-attribute-color: #999;
        --toggles-color: #999;
+       --toggle-filter: invert(100%);
        --search-input-focused-border-color: #5c6773; /* Same as `--border-color`. */
        --copy-path-button-color: #fff;
        --copy-path-img-filter: invert(70%);
@@ -86,6 +87,7 @@ Original by Dempfi (https://github.com/dempfi/ayu)
        --crate-search-hover-border: #e0e0e0;
        --source-sidebar-background-selected: #14191f;
        --source-sidebar-background-hover: #14191f;
+       --table-alt-row-background-color: #191f26;
 }
 
 h1, h2, h3, h4 {
@@ -158,15 +160,6 @@ body.source .example-wrap pre.rust a {
        background: #333;
 }
 
-details.rustdoc-toggle > summary::before {
-       filter: invert(100%);
-}
-
-.module-item .stab,
-.import-item .stab {
-       color: #000;
-}
-
 .result-name .primitive > i, .result-name .keyword > i {
        color: #788797;
 }
index d8929f32338643a1276b6bbf6994ca125a133afe..d945e956c533e20b52fea54d922924363acd449d 100644 (file)
@@ -16,6 +16,7 @@
        --right-side-color: grey;
        --code-attribute-color: #999;
        --toggles-color: #999;
+       --toggle-filter: invert(100%);
        --search-input-focused-border-color: #008dfd;
        --copy-path-button-color: #999;
        --copy-path-img-filter: invert(50%);
@@ -81,6 +82,7 @@
        --crate-search-hover-border: #2196f3;
        --source-sidebar-background-selected: #333;
        --source-sidebar-background-hover: #444;
+       --table-alt-row-background-color: #2A2A2A;
 }
 
 .content .item-info::before { color: #ccc; }
@@ -89,10 +91,6 @@ body.source .example-wrap pre.rust a {
        background: #333;
 }
 
-details.rustdoc-toggle > summary::before {
-       filter: invert(100%);
-}
-
 #titles > button:not(.selected) {
        background-color: #252525;
        border-top-color: #252525;
index 78a0cdcc3bc0578d92d2ccd68a0f140bb8cece2f..58955a79316af3f2485c68e681ba9ac247454934 100644 (file)
@@ -16,6 +16,7 @@
        --right-side-color: grey;
        --code-attribute-color: #999;
        --toggles-color: #999;
+       --toggle-filter: none;
        --search-input-focused-border-color: #66afe9;
        --copy-path-button-color: #999;
        --copy-path-img-filter: invert(50%);
@@ -78,6 +79,7 @@
        --crate-search-hover-border: #717171;
        --source-sidebar-background-selected: #fff;
        --source-sidebar-background-hover: #e0e0e0;
+       --table-alt-row-background-color: #F5F5F5;
 }
 
 .content .item-info::before { color: #ccc; }
index 623f46b109666facbd7a2a2d9400ae88620c95a8..152116089c7fc2c6f1c400f7f353fb16d879e66d 100644 (file)
@@ -622,7 +622,7 @@ function loadCss(cssUrl) {
         const innerToggle = document.getElementById(toggleAllDocsId);
         removeClass(innerToggle, "will-expand");
         onEachLazy(document.getElementsByClassName("rustdoc-toggle"), e => {
-            if (!hasClass(e, "type-contents-toggle")) {
+            if (!hasClass(e, "type-contents-toggle") && !hasClass(e, "more-examples-toggle")) {
                 e.open = true;
             }
         });
index d0fd115fd15c6d2fada74ce93e19d9f8bd34b92b..7a3a9c5f3400190fb62ec8ea3ee904171a06d048 100644 (file)
@@ -3,25 +3,33 @@
 "use strict";
 
 (function() {
-    // Number of lines shown when code viewer is not expanded
-    const MAX_LINES = 10;
+    // Number of lines shown when code viewer is not expanded.
+    // DEFAULT is the first example shown by default, while HIDDEN is
+    // the examples hidden beneath the "More examples" toggle.
+    //
+    // NOTE: these values MUST be synchronized with certain rules in rustdoc.css!
+    const DEFAULT_MAX_LINES = 5;
+    const HIDDEN_MAX_LINES = 10;
 
     // Scroll code block to the given code location
-    function scrollToLoc(elt, loc) {
+    function scrollToLoc(elt, loc, isHidden) {
         const lines = elt.querySelector(".src-line-numbers");
         let scrollOffset;
 
         // If the block is greater than the size of the viewer,
         // then scroll to the top of the block. Otherwise scroll
         // to the middle of the block.
-        if (loc[1] - loc[0] > MAX_LINES) {
+        const maxLines = isHidden ? HIDDEN_MAX_LINES : DEFAULT_MAX_LINES;
+        if (loc[1] - loc[0] > maxLines) {
             const line = Math.max(0, loc[0] - 1);
             scrollOffset = lines.children[line].offsetTop;
         } else {
             const wrapper = elt.querySelector(".code-wrapper");
             const halfHeight = wrapper.offsetHeight / 2;
-            const offsetMid = (lines.children[loc[0]].offsetTop
-                             + lines.children[loc[1]].offsetTop) / 2;
+            const offsetTop = lines.children[loc[0]].offsetTop;
+            const lastLine = lines.children[loc[1]];
+            const offsetBot = lastLine.offsetTop + lastLine.offsetHeight;
+            const offsetMid = (offsetTop + offsetBot) / 2;
             scrollOffset = offsetMid - halfHeight;
         }
 
@@ -29,7 +37,7 @@
         elt.querySelector(".rust").scrollTo(0, scrollOffset);
     }
 
-    function updateScrapedExample(example) {
+    function updateScrapedExample(example, isHidden) {
         const locs = JSON.parse(example.attributes.getNamedItem("data-locs").textContent);
         let locIndex = 0;
         const highlights = Array.prototype.slice.call(example.querySelectorAll(".highlight"));
@@ -40,7 +48,7 @@
             const onChangeLoc = changeIndex => {
                 removeClass(highlights[locIndex], "focus");
                 changeIndex();
-                scrollToLoc(example, locs[locIndex][0]);
+                scrollToLoc(example, locs[locIndex][0], isHidden);
                 addClass(highlights[locIndex], "focus");
 
                 const url = locs[locIndex][1];
@@ -57,7 +65,7 @@
                     });
                 });
 
-            example.querySelector("next")
+            example.querySelector(".next")
                 .addEventListener("click", () => {
                     onChangeLoc(() => {
                         locIndex = (locIndex + 1) % locs.length;
@@ -70,7 +78,7 @@
             expandButton.addEventListener("click", () => {
                 if (hasClass(example, "expanded")) {
                     removeClass(example, "expanded");
-                    scrollToLoc(example, locs[0][0]);
+                    scrollToLoc(example, locs[0][0], isHidden);
                 } else {
                     addClass(example, "expanded");
                 }
         }
 
         // Start with the first example in view
-        scrollToLoc(example, locs[0][0]);
+        scrollToLoc(example, locs[0][0], isHidden);
     }
 
     const firstExamples = document.querySelectorAll(".scraped-example-list > .scraped-example");
-    onEachLazy(firstExamples, updateScrapedExample);
+    onEachLazy(firstExamples, el => updateScrapedExample(el, false));
     onEachLazy(document.querySelectorAll(".more-examples-toggle"), toggle => {
         // Allow users to click the left border of the <details> section to close it,
         // since the section can be large and finding the [+] button is annoying.
             // depends on offsetHeight, a property that requires an element to be visible to
             // compute correctly.
             setTimeout(() => {
-                onEachLazy(moreExamples, updateScrapedExample);
+                onEachLazy(moreExamples, el => updateScrapedExample(el, true));
             });
         }, {once: true});
     });
index 035b2e18b00ebeaf1839e4ce3b4e85a9158e4e62..002d19ec9b67dae6c0b3724e6b46aac4213f9766 100644 (file)
@@ -1,4 +1,4 @@
-Rustdoc will automatically scrape examples of documented items from the `examples/` directory of a project. These examples will be included within the generated documentation for that item. For example, if your library contains a public function:
+Rustdoc will automatically scrape examples of documented items from a project's source code. These examples will be included within the generated documentation for that item. For example, if your library contains a public function:
 
 ```rust
 // src/lib.rs
@@ -16,6 +16,7 @@ fn main() {
 
 Then this code snippet will be included in the documentation for `a_func`.
 
+
 ## How to read scraped examples
 
 Scraped examples are shown as blocks of code from a given file. The relevant item will be highlighted. If the file is larger than a couple lines, only a small window will be shown which you can expand by clicking &varr; in the top-right. If a file contains multiple instances of an item, you can use the &pr; and &sc; buttons to toggle through each instance.
@@ -25,7 +26,7 @@ If there is more than one file that contains examples, then you should click "Mo
 
 ## How Rustdoc scrapes examples
 
-When you run `cargo doc`, Rustdoc will analyze all the crates that match Cargo's `--examples` filter for instances of items that occur in the crates being documented. Then Rustdoc will include the source code of these instances in the generated documentation.
+When you run `cargo doc -Zunstable-options -Zrustdoc-scrape-examples`, Rustdoc will analyze all the documented crates for uses of documented items. Then Rustdoc will include the source code of these instances in the generated documentation.
 
 Rustdoc has a few techniques to ensure this doesn't overwhelm documentation readers, and that it doesn't blow up the page size:
 
index 1f87f95563ad550d789ec580f3d4eff64fcb71ce..b48b82307ebc3c672a87b2af3765250ea6081748 100644 (file)
@@ -130,4 +130,4 @@ pub(crate) fn for_each<E>(f: impl Fn(&StaticFile) -> Result<(), E>) -> Result<()
     nanum_barun_gothic_license => "static/fonts/NanumBarunGothic-LICENSE.txt",
 }
 
-pub(crate) static SCRAPE_EXAMPLES_HELP_MD: &str = include_str!("static/js/scrape-examples.js");
+pub(crate) static SCRAPE_EXAMPLES_HELP_MD: &str = include_str!("static/scrape-examples-help.md");
index e4df1332521a782750061c446d6382d8b96f007a..1196f944faad2d26981b806023fe739cfaacc953 100644 (file)
@@ -99,53 +99,6 @@ fn get_impls(&mut self, id: DefId) -> Vec<types::Id> {
             })
             .unwrap_or_default()
     }
-
-    fn get_trait_items(&mut self) -> Vec<(types::Id, types::Item)> {
-        debug!("Adding foreign trait items");
-        Rc::clone(&self.cache)
-            .traits
-            .iter()
-            .filter_map(|(&id, trait_item)| {
-                // only need to synthesize items for external traits
-                if !id.is_local() {
-                    for item in &trait_item.items {
-                        trace!("Adding subitem to {id:?}: {:?}", item.item_id);
-                        self.item(item.clone()).unwrap();
-                    }
-                    let item_id = from_item_id(id.into(), self.tcx);
-                    Some((
-                        item_id.clone(),
-                        types::Item {
-                            id: item_id,
-                            crate_id: id.krate.as_u32(),
-                            name: self
-                                .cache
-                                .paths
-                                .get(&id)
-                                .unwrap_or_else(|| {
-                                    self.cache
-                                        .external_paths
-                                        .get(&id)
-                                        .expect("Trait should either be in local or external paths")
-                                })
-                                .0
-                                .last()
-                                .map(|s| s.to_string()),
-                            visibility: types::Visibility::Public,
-                            inner: types::ItemEnum::Trait(trait_item.clone().into_tcx(self.tcx)),
-                            span: None,
-                            docs: Default::default(),
-                            links: Default::default(),
-                            attrs: Default::default(),
-                            deprecation: Default::default(),
-                        },
-                    ))
-                } else {
-                    None
-                }
-            })
-            .collect()
-    }
 }
 
 impl<'tcx> FormatRenderer<'tcx> for JsonRenderer<'tcx> {
@@ -225,10 +178,10 @@ fn item(&mut self, item: clean::Item) -> Result<(), Error> {
 
                 types::ItemEnum::Function(_)
                 | types::ItemEnum::Module(_)
+                | types::ItemEnum::Import(_)
                 | types::ItemEnum::AssocConst { .. }
                 | types::ItemEnum::AssocType { .. } => true,
                 types::ItemEnum::ExternCrate { .. }
-                | types::ItemEnum::Import(_)
                 | types::ItemEnum::StructField(_)
                 | types::ItemEnum::Variant(_)
                 | types::ItemEnum::TraitAlias(_)
@@ -276,11 +229,7 @@ fn after_krate(&mut self) -> Result<(), Error> {
 
         let e = ExternalCrate { crate_num: LOCAL_CRATE };
 
-        // FIXME(adotinthevoid): Remove this, as it's not consistent with not
-        // inlining foreign items.
-        let foreign_trait_items = self.get_trait_items();
-        let mut index = (*self.index).clone().into_inner();
-        index.extend(foreign_trait_items);
+        let index = (*self.index).clone().into_inner();
 
         debug!("Constructing Output");
         // This needs to be the default HashMap for compatibility with the public interface for
index 1a84ec650474d28b916f4c62cfab234515490f81..ef1d7da5a341cf8ca191f171ba22dba6cd462abc 100644 (file)
@@ -674,7 +674,7 @@ fn usage(argv0: &str) {
 
 fn wrap_return(diag: &rustc_errors::Handler, res: Result<(), String>) -> MainResult {
     match res {
-        Ok(()) => Ok(()),
+        Ok(()) => diag.has_errors().map_or(Ok(()), Err),
         Err(err) => {
             let reported = diag.struct_err(&err).emit();
             Err(reported)
@@ -689,7 +689,7 @@ fn run_renderer<'tcx, T: formats::FormatRenderer<'tcx>>(
     tcx: TyCtxt<'tcx>,
 ) -> MainResult {
     match formats::run_format::<T>(krate, renderopts, cache, tcx) {
-        Ok(_) => Ok(()),
+        Ok(_) => tcx.sess.has_errors().map_or(Ok(()), Err),
         Err(e) => {
             let mut msg =
                 tcx.sess.struct_err(&format!("couldn't generate documentation: {}", e.error));
@@ -774,6 +774,7 @@ fn main_args(at_args: &[String]) -> MainResult {
     let output_format = options.output_format;
     let externs = options.externs.clone();
     let scrape_examples_options = options.scrape_examples_options.clone();
+    let bin_crate = options.bin_crate;
 
     let config = core::create_config(options);
 
@@ -781,10 +782,7 @@ fn main_args(at_args: &[String]) -> MainResult {
         let sess = compiler.session();
 
         if sess.opts.describe_lints {
-            let mut lint_store = rustc_lint::new_lint_store(
-                sess.opts.unstable_opts.no_interleave_lints,
-                sess.enable_internal_lints(),
-            );
+            let mut lint_store = rustc_lint::new_lint_store(sess.enable_internal_lints());
             let registered_lints = if let Some(register_lints) = compiler.register_lints() {
                 register_lints(sess, &mut lint_store);
                 true
@@ -835,7 +833,14 @@ fn main_args(at_args: &[String]) -> MainResult {
                 info!("finished with rustc");
 
                 if let Some(options) = scrape_examples_options {
-                    return scrape_examples::run(krate, render_opts, cache, tcx, options);
+                    return scrape_examples::run(
+                        krate,
+                        render_opts,
+                        cache,
+                        tcx,
+                        options,
+                        bin_crate,
+                    );
                 }
 
                 cache.crate_version = crate_version;
diff --git a/src/librustdoc/passes/bare_urls.rs b/src/librustdoc/passes/bare_urls.rs
deleted file mode 100644 (file)
index 7ff3cce..0000000
+++ /dev/null
@@ -1,110 +0,0 @@
-//! Detects links that are not linkified, e.g., in Markdown such as `Go to https://example.com/.`
-//! Suggests wrapping the link with angle brackets: `Go to <https://example.com/>.` to linkify it.
-use super::Pass;
-use crate::clean::*;
-use crate::core::DocContext;
-use crate::html::markdown::main_body_opts;
-use crate::visit::DocVisitor;
-use core::ops::Range;
-use pulldown_cmark::{Event, Parser, Tag};
-use regex::Regex;
-use rustc_errors::Applicability;
-use std::mem;
-use std::sync::LazyLock;
-
-pub(crate) const CHECK_BARE_URLS: Pass = Pass {
-    name: "check-bare-urls",
-    run: check_bare_urls,
-    description: "detects URLs that are not hyperlinks",
-};
-
-static URL_REGEX: LazyLock<Regex> = LazyLock::new(|| {
-    Regex::new(concat!(
-        r"https?://",                          // url scheme
-        r"([-a-zA-Z0-9@:%._\+~#=]{2,256}\.)+", // one or more subdomains
-        r"[a-zA-Z]{2,63}",                     // root domain
-        r"\b([-a-zA-Z0-9@:%_\+.~#?&/=]*)"      // optional query or url fragments
-    ))
-    .expect("failed to build regex")
-});
-
-struct BareUrlsLinter<'a, 'tcx> {
-    cx: &'a mut DocContext<'tcx>,
-}
-
-impl<'a, 'tcx> BareUrlsLinter<'a, 'tcx> {
-    fn find_raw_urls(
-        &self,
-        text: &str,
-        range: Range<usize>,
-        f: &impl Fn(&DocContext<'_>, &str, &str, Range<usize>),
-    ) {
-        trace!("looking for raw urls in {}", text);
-        // For now, we only check "full" URLs (meaning, starting with "http://" or "https://").
-        for match_ in URL_REGEX.find_iter(text) {
-            let url = match_.as_str();
-            let url_range = match_.range();
-            f(
-                self.cx,
-                "this URL is not a hyperlink",
-                url,
-                Range { start: range.start + url_range.start, end: range.start + url_range.end },
-            );
-        }
-    }
-}
-
-pub(crate) fn check_bare_urls(krate: Crate, cx: &mut DocContext<'_>) -> Crate {
-    BareUrlsLinter { cx }.visit_crate(&krate);
-    krate
-}
-
-impl<'a, 'tcx> DocVisitor for BareUrlsLinter<'a, 'tcx> {
-    fn visit_item(&mut self, item: &Item) {
-        let Some(hir_id) = DocContext::as_local_hir_id(self.cx.tcx, item.item_id)
-        else {
-            // If non-local, no need to check anything.
-            return;
-        };
-        let dox = item.attrs.collapsed_doc_value().unwrap_or_default();
-        if !dox.is_empty() {
-            let report_diag = |cx: &DocContext<'_>, msg: &str, url: &str, range: Range<usize>| {
-                let sp = super::source_span_for_markdown_range(cx.tcx, &dox, &range, &item.attrs)
-                    .unwrap_or_else(|| item.attr_span(cx.tcx));
-                cx.tcx.struct_span_lint_hir(crate::lint::BARE_URLS, hir_id, sp, msg, |lint| {
-                    lint.note("bare URLs are not automatically turned into clickable links")
-                        .span_suggestion(
-                            sp,
-                            "use an automatic link instead",
-                            format!("<{}>", url),
-                            Applicability::MachineApplicable,
-                        )
-                });
-            };
-
-            let mut p = Parser::new_ext(&dox, main_body_opts()).into_offset_iter();
-
-            while let Some((event, range)) = p.next() {
-                match event {
-                    Event::Text(s) => self.find_raw_urls(&s, range, &report_diag),
-                    // We don't want to check the text inside code blocks or links.
-                    Event::Start(tag @ (Tag::CodeBlock(_) | Tag::Link(..))) => {
-                        while let Some((event, _)) = p.next() {
-                            match event {
-                                Event::End(end)
-                                    if mem::discriminant(&end) == mem::discriminant(&tag) =>
-                                {
-                                    break;
-                                }
-                                _ => {}
-                            }
-                        }
-                    }
-                    _ => {}
-                }
-            }
-        }
-
-        self.visit_item_recur(item)
-    }
-}
diff --git a/src/librustdoc/passes/check_code_block_syntax.rs b/src/librustdoc/passes/check_code_block_syntax.rs
deleted file mode 100644 (file)
index 2e651b5..0000000
+++ /dev/null
@@ -1,209 +0,0 @@
-//! Validates syntax inside Rust code blocks (\`\`\`rust).
-use rustc_data_structures::sync::{Lock, Lrc};
-use rustc_errors::{
-    emitter::Emitter,
-    translation::{to_fluent_args, Translate},
-    Applicability, Diagnostic, Handler, LazyFallbackBundle,
-};
-use rustc_parse::parse_stream_from_source_str;
-use rustc_session::parse::ParseSess;
-use rustc_span::hygiene::{AstPass, ExpnData, ExpnKind, LocalExpnId};
-use rustc_span::source_map::{FilePathMapping, SourceMap};
-use rustc_span::{FileName, InnerSpan, DUMMY_SP};
-
-use crate::clean;
-use crate::core::DocContext;
-use crate::html::markdown::{self, RustCodeBlock};
-use crate::passes::Pass;
-use crate::visit::DocVisitor;
-
-pub(crate) const CHECK_CODE_BLOCK_SYNTAX: Pass = Pass {
-    name: "check-code-block-syntax",
-    run: check_code_block_syntax,
-    description: "validates syntax inside Rust code blocks",
-};
-
-pub(crate) fn check_code_block_syntax(
-    krate: clean::Crate,
-    cx: &mut DocContext<'_>,
-) -> clean::Crate {
-    SyntaxChecker { cx }.visit_crate(&krate);
-    krate
-}
-
-struct SyntaxChecker<'a, 'tcx> {
-    cx: &'a DocContext<'tcx>,
-}
-
-impl<'a, 'tcx> SyntaxChecker<'a, 'tcx> {
-    fn check_rust_syntax(&self, item: &clean::Item, dox: &str, code_block: RustCodeBlock) {
-        let buffer = Lrc::new(Lock::new(Buffer::default()));
-        let fallback_bundle =
-            rustc_errors::fallback_fluent_bundle(rustc_errors::DEFAULT_LOCALE_RESOURCES, false);
-        let emitter = BufferEmitter { buffer: Lrc::clone(&buffer), fallback_bundle };
-
-        let sm = Lrc::new(SourceMap::new(FilePathMapping::empty()));
-        let handler = Handler::with_emitter(false, None, Box::new(emitter));
-        let source = dox[code_block.code].to_owned();
-        let sess = ParseSess::with_span_handler(handler, sm);
-
-        let edition = code_block.lang_string.edition.unwrap_or_else(|| self.cx.tcx.sess.edition());
-        let expn_data = ExpnData::default(
-            ExpnKind::AstPass(AstPass::TestHarness),
-            DUMMY_SP,
-            edition,
-            None,
-            None,
-        );
-        let expn_id =
-            self.cx.tcx.with_stable_hashing_context(|hcx| LocalExpnId::fresh(expn_data, hcx));
-        let span = DUMMY_SP.fresh_expansion(expn_id);
-
-        let is_empty = rustc_driver::catch_fatal_errors(|| {
-            parse_stream_from_source_str(
-                FileName::Custom(String::from("doctest")),
-                source,
-                &sess,
-                Some(span),
-            )
-            .is_empty()
-        })
-        .unwrap_or(false);
-        let buffer = buffer.borrow();
-
-        if !buffer.has_errors && !is_empty {
-            // No errors in a non-empty program.
-            return;
-        }
-
-        let Some(local_id) = item.item_id.as_def_id().and_then(|x| x.as_local())
-        else {
-            // We don't need to check the syntax for other crates so returning
-            // without doing anything should not be a problem.
-            return;
-        };
-
-        let hir_id = self.cx.tcx.hir().local_def_id_to_hir_id(local_id);
-        let empty_block = code_block.lang_string == Default::default() && code_block.is_fenced;
-        let is_ignore = code_block.lang_string.ignore != markdown::Ignore::None;
-
-        // The span and whether it is precise or not.
-        let (sp, precise_span) = match super::source_span_for_markdown_range(
-            self.cx.tcx,
-            dox,
-            &code_block.range,
-            &item.attrs,
-        ) {
-            Some(sp) => (sp, true),
-            None => (item.attr_span(self.cx.tcx), false),
-        };
-
-        let msg = if buffer.has_errors {
-            "could not parse code block as Rust code"
-        } else {
-            "Rust code block is empty"
-        };
-
-        // Finally build and emit the completed diagnostic.
-        // All points of divergence have been handled earlier so this can be
-        // done the same way whether the span is precise or not.
-        self.cx.tcx.struct_span_lint_hir(
-            crate::lint::INVALID_RUST_CODEBLOCKS,
-            hir_id,
-            sp,
-            msg,
-            |lint| {
-                let explanation = if is_ignore {
-                    "`ignore` code blocks require valid Rust code for syntax highlighting; \
-                    mark blocks that do not contain Rust code as text"
-                } else {
-                    "mark blocks that do not contain Rust code as text"
-                };
-
-                if precise_span {
-                    if is_ignore {
-                        // giving an accurate suggestion is hard because `ignore` might not have come first in the list.
-                        // just give a `help` instead.
-                        lint.span_help(
-                            sp.from_inner(InnerSpan::new(0, 3)),
-                            &format!("{}: ```text", explanation),
-                        );
-                    } else if empty_block {
-                        lint.span_suggestion(
-                            sp.from_inner(InnerSpan::new(0, 3)).shrink_to_hi(),
-                            explanation,
-                            "text",
-                            Applicability::MachineApplicable,
-                        );
-                    }
-                } else if empty_block || is_ignore {
-                    lint.help(&format!("{}: ```text", explanation));
-                }
-
-                // FIXME(#67563): Provide more context for these errors by displaying the spans inline.
-                for message in buffer.messages.iter() {
-                    lint.note(message);
-                }
-
-                lint
-            },
-        );
-    }
-}
-
-impl<'a, 'tcx> DocVisitor for SyntaxChecker<'a, 'tcx> {
-    fn visit_item(&mut self, item: &clean::Item) {
-        if let Some(dox) = &item.attrs.collapsed_doc_value() {
-            let sp = item.attr_span(self.cx.tcx);
-            let extra = crate::html::markdown::ExtraInfo::new_did(
-                self.cx.tcx,
-                item.item_id.expect_def_id(),
-                sp,
-            );
-            for code_block in markdown::rust_code_blocks(dox, &extra) {
-                self.check_rust_syntax(item, dox, code_block);
-            }
-        }
-
-        self.visit_item_recur(item)
-    }
-}
-
-#[derive(Default)]
-struct Buffer {
-    messages: Vec<String>,
-    has_errors: bool,
-}
-
-struct BufferEmitter {
-    buffer: Lrc<Lock<Buffer>>,
-    fallback_bundle: LazyFallbackBundle,
-}
-
-impl Translate for BufferEmitter {
-    fn fluent_bundle(&self) -> Option<&Lrc<rustc_errors::FluentBundle>> {
-        None
-    }
-
-    fn fallback_fluent_bundle(&self) -> &rustc_errors::FluentBundle {
-        &**self.fallback_bundle
-    }
-}
-
-impl Emitter for BufferEmitter {
-    fn emit_diagnostic(&mut self, diag: &Diagnostic) {
-        let mut buffer = self.buffer.borrow_mut();
-
-        let fluent_args = to_fluent_args(diag.args());
-        let translated_main_message = self.translate_message(&diag.message[0].0, &fluent_args);
-
-        buffer.messages.push(format!("error from rustc: {}", translated_main_message));
-        if diag.is_error() {
-            buffer.has_errors = true;
-        }
-    }
-
-    fn source_map(&self) -> Option<&Lrc<SourceMap>> {
-        None
-    }
-}
index d57f981d51a84fac39729d530f055d8324a8d68c..79db3c6c3e78699845da1046efadd30e849c33ed 100644 (file)
 };
 
 pub(crate) fn collect_trait_impls(mut krate: Crate, cx: &mut DocContext<'_>) -> Crate {
+    // We need to check if there are errors before running this pass because it would crash when
+    // we try to get auto and blanket implementations.
+    if cx.tcx.sess.diagnostic().has_errors_or_lint_errors().is_some() {
+        return krate;
+    }
+
     let synth_impls = cx.sess().time("collect_synthetic_impls", || {
         let mut synth = SyntheticImplCollector { cx, impls: Vec::new() };
         synth.visit_crate(&krate);
diff --git a/src/librustdoc/passes/html_tags.rs b/src/librustdoc/passes/html_tags.rs
deleted file mode 100644 (file)
index a89ed7c..0000000
+++ /dev/null
@@ -1,430 +0,0 @@
-//! Detects invalid HTML (like an unclosed `<span>`) in doc comments.
-use super::Pass;
-use crate::clean::*;
-use crate::core::DocContext;
-use crate::html::markdown::main_body_opts;
-use crate::visit::DocVisitor;
-
-use pulldown_cmark::{BrokenLink, Event, LinkType, Parser, Tag};
-
-use std::iter::Peekable;
-use std::ops::Range;
-use std::str::CharIndices;
-
-pub(crate) const CHECK_INVALID_HTML_TAGS: Pass = Pass {
-    name: "check-invalid-html-tags",
-    run: check_invalid_html_tags,
-    description: "detects invalid HTML tags in doc comments",
-};
-
-struct InvalidHtmlTagsLinter<'a, 'tcx> {
-    cx: &'a mut DocContext<'tcx>,
-}
-
-pub(crate) fn check_invalid_html_tags(krate: Crate, cx: &mut DocContext<'_>) -> Crate {
-    let mut coll = InvalidHtmlTagsLinter { cx };
-    coll.visit_crate(&krate);
-    krate
-}
-
-const ALLOWED_UNCLOSED: &[&str] = &[
-    "area", "base", "br", "col", "embed", "hr", "img", "input", "keygen", "link", "meta", "param",
-    "source", "track", "wbr",
-];
-
-fn drop_tag(
-    tags: &mut Vec<(String, Range<usize>)>,
-    tag_name: String,
-    range: Range<usize>,
-    f: &impl Fn(&str, &Range<usize>, bool),
-) {
-    let tag_name_low = tag_name.to_lowercase();
-    if let Some(pos) = tags.iter().rposition(|(t, _)| t.to_lowercase() == tag_name_low) {
-        // If the tag is nested inside a "<script>" or a "<style>" tag, no warning should
-        // be emitted.
-        let should_not_warn = tags.iter().take(pos + 1).any(|(at, _)| {
-            let at = at.to_lowercase();
-            at == "script" || at == "style"
-        });
-        for (last_tag_name, last_tag_span) in tags.drain(pos + 1..) {
-            if should_not_warn {
-                continue;
-            }
-            let last_tag_name_low = last_tag_name.to_lowercase();
-            if ALLOWED_UNCLOSED.contains(&last_tag_name_low.as_str()) {
-                continue;
-            }
-            // `tags` is used as a queue, meaning that everything after `pos` is included inside it.
-            // So `<h2><h3></h2>` will look like `["h2", "h3"]`. So when closing `h2`, we will still
-            // have `h3`, meaning the tag wasn't closed as it should have.
-            f(&format!("unclosed HTML tag `{}`", last_tag_name), &last_tag_span, true);
-        }
-        // Remove the `tag_name` that was originally closed
-        tags.pop();
-    } else {
-        // It can happen for example in this case: `<h2></script></h2>` (the `h2` tag isn't required
-        // but it helps for the visualization).
-        f(&format!("unopened HTML tag `{}`", tag_name), &range, false);
-    }
-}
-
-fn extract_path_backwards(text: &str, end_pos: usize) -> Option<usize> {
-    use rustc_lexer::{is_id_continue, is_id_start};
-    let mut current_pos = end_pos;
-    loop {
-        if current_pos >= 2 && text[..current_pos].ends_with("::") {
-            current_pos -= 2;
-        }
-        let new_pos = text[..current_pos]
-            .char_indices()
-            .rev()
-            .take_while(|(_, c)| is_id_start(*c) || is_id_continue(*c))
-            .reduce(|_accum, item| item)
-            .and_then(|(new_pos, c)| is_id_start(c).then_some(new_pos));
-        if let Some(new_pos) = new_pos {
-            if current_pos != new_pos {
-                current_pos = new_pos;
-                continue;
-            }
-        }
-        break;
-    }
-    if current_pos == end_pos { None } else { Some(current_pos) }
-}
-
-fn extract_path_forward(text: &str, start_pos: usize) -> Option<usize> {
-    use rustc_lexer::{is_id_continue, is_id_start};
-    let mut current_pos = start_pos;
-    loop {
-        if current_pos < text.len() && text[current_pos..].starts_with("::") {
-            current_pos += 2;
-        } else {
-            break;
-        }
-        let mut chars = text[current_pos..].chars();
-        if let Some(c) = chars.next() {
-            if is_id_start(c) {
-                current_pos += c.len_utf8();
-            } else {
-                break;
-            }
-        }
-        while let Some(c) = chars.next() {
-            if is_id_continue(c) {
-                current_pos += c.len_utf8();
-            } else {
-                break;
-            }
-        }
-    }
-    if current_pos == start_pos { None } else { Some(current_pos) }
-}
-
-fn is_valid_for_html_tag_name(c: char, is_empty: bool) -> bool {
-    // https://spec.commonmark.org/0.30/#raw-html
-    //
-    // > A tag name consists of an ASCII letter followed by zero or more ASCII letters, digits, or
-    // > hyphens (-).
-    c.is_ascii_alphabetic() || !is_empty && (c == '-' || c.is_ascii_digit())
-}
-
-fn extract_html_tag(
-    tags: &mut Vec<(String, Range<usize>)>,
-    text: &str,
-    range: &Range<usize>,
-    start_pos: usize,
-    iter: &mut Peekable<CharIndices<'_>>,
-    f: &impl Fn(&str, &Range<usize>, bool),
-) {
-    let mut tag_name = String::new();
-    let mut is_closing = false;
-    let mut prev_pos = start_pos;
-
-    loop {
-        let (pos, c) = match iter.peek() {
-            Some((pos, c)) => (*pos, *c),
-            // In case we reached the of the doc comment, we want to check that it's an
-            // unclosed HTML tag. For example "/// <h3".
-            None => (prev_pos, '\0'),
-        };
-        prev_pos = pos;
-        // Checking if this is a closing tag (like `</a>` for `<a>`).
-        if c == '/' && tag_name.is_empty() {
-            is_closing = true;
-        } else if is_valid_for_html_tag_name(c, tag_name.is_empty()) {
-            tag_name.push(c);
-        } else {
-            if !tag_name.is_empty() {
-                let mut r = Range { start: range.start + start_pos, end: range.start + pos };
-                if c == '>' {
-                    // In case we have a tag without attribute, we can consider the span to
-                    // refer to it fully.
-                    r.end += 1;
-                }
-                if is_closing {
-                    // In case we have "</div >" or even "</div         >".
-                    if c != '>' {
-                        if !c.is_whitespace() {
-                            // It seems like it's not a valid HTML tag.
-                            break;
-                        }
-                        let mut found = false;
-                        for (new_pos, c) in text[pos..].char_indices() {
-                            if !c.is_whitespace() {
-                                if c == '>' {
-                                    r.end = range.start + new_pos + 1;
-                                    found = true;
-                                }
-                                break;
-                            }
-                        }
-                        if !found {
-                            break;
-                        }
-                    }
-                    drop_tag(tags, tag_name, r, f);
-                } else {
-                    let mut is_self_closing = false;
-                    let mut quote_pos = None;
-                    if c != '>' {
-                        let mut quote = None;
-                        let mut after_eq = false;
-                        for (i, c) in text[pos..].char_indices() {
-                            if !c.is_whitespace() {
-                                if let Some(q) = quote {
-                                    if c == q {
-                                        quote = None;
-                                        quote_pos = None;
-                                        after_eq = false;
-                                    }
-                                } else if c == '>' {
-                                    break;
-                                } else if c == '/' && !after_eq {
-                                    is_self_closing = true;
-                                } else {
-                                    if is_self_closing {
-                                        is_self_closing = false;
-                                    }
-                                    if (c == '"' || c == '\'') && after_eq {
-                                        quote = Some(c);
-                                        quote_pos = Some(pos + i);
-                                    } else if c == '=' {
-                                        after_eq = true;
-                                    }
-                                }
-                            } else if quote.is_none() {
-                                after_eq = false;
-                            }
-                        }
-                    }
-                    if let Some(quote_pos) = quote_pos {
-                        let qr = Range { start: quote_pos, end: quote_pos };
-                        f(
-                            &format!("unclosed quoted HTML attribute on tag `{}`", tag_name),
-                            &qr,
-                            false,
-                        );
-                    }
-                    if is_self_closing {
-                        // https://html.spec.whatwg.org/#parse-error-non-void-html-element-start-tag-with-trailing-solidus
-                        let valid = ALLOWED_UNCLOSED.contains(&&tag_name[..])
-                            || tags.iter().take(pos + 1).any(|(at, _)| {
-                                let at = at.to_lowercase();
-                                at == "svg" || at == "math"
-                            });
-                        if !valid {
-                            f(&format!("invalid self-closing HTML tag `{}`", tag_name), &r, false);
-                        }
-                    } else {
-                        tags.push((tag_name, r));
-                    }
-                }
-            }
-            break;
-        }
-        iter.next();
-    }
-}
-
-fn extract_tags(
-    tags: &mut Vec<(String, Range<usize>)>,
-    text: &str,
-    range: Range<usize>,
-    is_in_comment: &mut Option<Range<usize>>,
-    f: &impl Fn(&str, &Range<usize>, bool),
-) {
-    let mut iter = text.char_indices().peekable();
-
-    while let Some((start_pos, c)) = iter.next() {
-        if is_in_comment.is_some() {
-            if text[start_pos..].starts_with("-->") {
-                *is_in_comment = None;
-            }
-        } else if c == '<' {
-            if text[start_pos..].starts_with("<!--") {
-                // We skip the "!--" part. (Once `advance_by` is stable, might be nice to use it!)
-                iter.next();
-                iter.next();
-                iter.next();
-                *is_in_comment = Some(Range {
-                    start: range.start + start_pos,
-                    end: range.start + start_pos + 3,
-                });
-            } else {
-                extract_html_tag(tags, text, &range, start_pos, &mut iter, f);
-            }
-        }
-    }
-}
-
-impl<'a, 'tcx> DocVisitor for InvalidHtmlTagsLinter<'a, 'tcx> {
-    fn visit_item(&mut self, item: &Item) {
-        let tcx = self.cx.tcx;
-        let Some(hir_id) = DocContext::as_local_hir_id(tcx, item.item_id)
-        // If non-local, no need to check anything.
-        else { return };
-        let dox = item.attrs.collapsed_doc_value().unwrap_or_default();
-        if !dox.is_empty() {
-            let report_diag = |msg: &str, range: &Range<usize>, is_open_tag: bool| {
-                let sp = match super::source_span_for_markdown_range(tcx, &dox, range, &item.attrs)
-                {
-                    Some(sp) => sp,
-                    None => item.attr_span(tcx),
-                };
-                tcx.struct_span_lint_hir(crate::lint::INVALID_HTML_TAGS, hir_id, sp, msg, |lint| {
-                    use rustc_lint_defs::Applicability;
-                    // If a tag looks like `<this>`, it might actually be a generic.
-                    // We don't try to detect stuff `<like, this>` because that's not valid HTML,
-                    // and we don't try to detect stuff `<like this>` because that's not valid Rust.
-                    let mut generics_end = range.end;
-                    if let Some(Some(mut generics_start)) = (is_open_tag
-                        && dox[..generics_end].ends_with('>'))
-                    .then(|| extract_path_backwards(&dox, range.start))
-                    {
-                        while generics_start != 0
-                            && generics_end < dox.len()
-                            && dox.as_bytes()[generics_start - 1] == b'<'
-                            && dox.as_bytes()[generics_end] == b'>'
-                        {
-                            generics_end += 1;
-                            generics_start -= 1;
-                            if let Some(new_start) = extract_path_backwards(&dox, generics_start) {
-                                generics_start = new_start;
-                            }
-                            if let Some(new_end) = extract_path_forward(&dox, generics_end) {
-                                generics_end = new_end;
-                            }
-                        }
-                        if let Some(new_end) = extract_path_forward(&dox, generics_end) {
-                            generics_end = new_end;
-                        }
-                        let generics_sp = match super::source_span_for_markdown_range(
-                            tcx,
-                            &dox,
-                            &(generics_start..generics_end),
-                            &item.attrs,
-                        ) {
-                            Some(sp) => sp,
-                            None => item.attr_span(tcx),
-                        };
-                        // Sometimes, we only extract part of a path. For example, consider this:
-                        //
-                        //     <[u32] as IntoIter<u32>>::Item
-                        //                       ^^^^^ unclosed HTML tag `u32`
-                        //
-                        // We don't have any code for parsing fully-qualified trait paths.
-                        // In theory, we could add it, but doing it correctly would require
-                        // parsing the entire path grammar, which is problematic because of
-                        // overlap between the path grammar and Markdown.
-                        //
-                        // The example above shows that ambiguity. Is `[u32]` intended to be an
-                        // intra-doc link to the u32 primitive, or is it intended to be a slice?
-                        //
-                        // If the below conditional were removed, we would suggest this, which is
-                        // not what the user probably wants.
-                        //
-                        //     <[u32] as `IntoIter<u32>`>::Item
-                        //
-                        // We know that the user actually wants to wrap the whole thing in a code
-                        // block, but the only reason we know that is because `u32` does not, in
-                        // fact, implement IntoIter. If the example looks like this:
-                        //
-                        //     <[Vec<i32>] as IntoIter<i32>::Item
-                        //
-                        // The ideal fix would be significantly different.
-                        if (generics_start > 0 && dox.as_bytes()[generics_start - 1] == b'<')
-                            || (generics_end < dox.len() && dox.as_bytes()[generics_end] == b'>')
-                        {
-                            return lint;
-                        }
-                        // multipart form is chosen here because ``Vec<i32>`` would be confusing.
-                        lint.multipart_suggestion(
-                            "try marking as source code",
-                            vec![
-                                (generics_sp.shrink_to_lo(), String::from("`")),
-                                (generics_sp.shrink_to_hi(), String::from("`")),
-                            ],
-                            Applicability::MaybeIncorrect,
-                        );
-                    }
-
-                    lint
-                });
-            };
-
-            let mut tags = Vec::new();
-            let mut is_in_comment = None;
-            let mut in_code_block = false;
-
-            let link_names = item.link_names(&self.cx.cache);
-
-            let mut replacer = |broken_link: BrokenLink<'_>| {
-                if let Some(link) =
-                    link_names.iter().find(|link| *link.original_text == *broken_link.reference)
-                {
-                    Some((link.href.as_str().into(), link.new_text.as_str().into()))
-                } else if matches!(
-                    &broken_link.link_type,
-                    LinkType::Reference | LinkType::ReferenceUnknown
-                ) {
-                    // If the link is shaped [like][this], suppress any broken HTML in the [this] part.
-                    // The `broken_intra_doc_links` will report typos in there anyway.
-                    Some((
-                        broken_link.reference.to_string().into(),
-                        broken_link.reference.to_string().into(),
-                    ))
-                } else {
-                    None
-                }
-            };
-
-            let p =
-                Parser::new_with_broken_link_callback(&dox, main_body_opts(), Some(&mut replacer))
-                    .into_offset_iter();
-
-            for (event, range) in p {
-                match event {
-                    Event::Start(Tag::CodeBlock(_)) => in_code_block = true,
-                    Event::Html(text) if !in_code_block => {
-                        extract_tags(&mut tags, &text, range, &mut is_in_comment, &report_diag)
-                    }
-                    Event::End(Tag::CodeBlock(_)) => in_code_block = false,
-                    _ => {}
-                }
-            }
-
-            for (tag, range) in tags.iter().filter(|(t, _)| {
-                let t = t.to_lowercase();
-                !ALLOWED_UNCLOSED.contains(&t.as_str())
-            }) {
-                report_diag(&format!("unclosed HTML tag `{}`", tag), range, true);
-            }
-
-            if let Some(range) = is_in_comment {
-                report_diag("Unclosed HTML comment", &range, false);
-            }
-        }
-
-        self.visit_item_recur(item)
-    }
-}
diff --git a/src/librustdoc/passes/lint.rs b/src/librustdoc/passes/lint.rs
new file mode 100644 (file)
index 0000000..97031c4
--- /dev/null
@@ -0,0 +1,33 @@
+//! Runs several rustdoc lints, consolidating them into a single pass for
+//! efficiency and simplicity.
+
+mod bare_urls;
+mod check_code_block_syntax;
+mod html_tags;
+
+use super::Pass;
+use crate::clean::*;
+use crate::core::DocContext;
+use crate::visit::DocVisitor;
+
+pub(crate) const RUN_LINTS: Pass =
+    Pass { name: "run-lints", run: run_lints, description: "runs some of rustdoc's lints" };
+
+struct Linter<'a, 'tcx> {
+    cx: &'a mut DocContext<'tcx>,
+}
+
+pub(crate) fn run_lints(krate: Crate, cx: &mut DocContext<'_>) -> Crate {
+    Linter { cx }.visit_crate(&krate);
+    krate
+}
+
+impl<'a, 'tcx> DocVisitor for Linter<'a, 'tcx> {
+    fn visit_item(&mut self, item: &Item) {
+        bare_urls::visit_item(self.cx, item);
+        check_code_block_syntax::visit_item(self.cx, item);
+        html_tags::visit_item(self.cx, item);
+
+        self.visit_item_recur(item)
+    }
+}
diff --git a/src/librustdoc/passes/lint/bare_urls.rs b/src/librustdoc/passes/lint/bare_urls.rs
new file mode 100644 (file)
index 0000000..423230c
--- /dev/null
@@ -0,0 +1,89 @@
+//! Detects links that are not linkified, e.g., in Markdown such as `Go to https://example.com/.`
+//! Suggests wrapping the link with angle brackets: `Go to <https://example.com/>.` to linkify it.
+
+use crate::clean::*;
+use crate::core::DocContext;
+use crate::html::markdown::main_body_opts;
+use crate::passes::source_span_for_markdown_range;
+use core::ops::Range;
+use pulldown_cmark::{Event, Parser, Tag};
+use regex::Regex;
+use rustc_errors::Applicability;
+use std::mem;
+use std::sync::LazyLock;
+
+pub(super) fn visit_item(cx: &DocContext<'_>, item: &Item) {
+    let Some(hir_id) = DocContext::as_local_hir_id(cx.tcx, item.item_id)
+        else {
+            // If non-local, no need to check anything.
+            return;
+        };
+    let dox = item.attrs.collapsed_doc_value().unwrap_or_default();
+    if !dox.is_empty() {
+        let report_diag = |cx: &DocContext<'_>, msg: &str, url: &str, range: Range<usize>| {
+            let sp = source_span_for_markdown_range(cx.tcx, &dox, &range, &item.attrs)
+                .unwrap_or_else(|| item.attr_span(cx.tcx));
+            cx.tcx.struct_span_lint_hir(crate::lint::BARE_URLS, hir_id, sp, msg, |lint| {
+                lint.note("bare URLs are not automatically turned into clickable links")
+                    .span_suggestion(
+                        sp,
+                        "use an automatic link instead",
+                        format!("<{}>", url),
+                        Applicability::MachineApplicable,
+                    )
+            });
+        };
+
+        let mut p = Parser::new_ext(&dox, main_body_opts()).into_offset_iter();
+
+        while let Some((event, range)) = p.next() {
+            match event {
+                Event::Text(s) => find_raw_urls(cx, &s, range, &report_diag),
+                // We don't want to check the text inside code blocks or links.
+                Event::Start(tag @ (Tag::CodeBlock(_) | Tag::Link(..))) => {
+                    while let Some((event, _)) = p.next() {
+                        match event {
+                            Event::End(end)
+                                if mem::discriminant(&end) == mem::discriminant(&tag) =>
+                            {
+                                break;
+                            }
+                            _ => {}
+                        }
+                    }
+                }
+                _ => {}
+            }
+        }
+    }
+}
+
+static URL_REGEX: LazyLock<Regex> = LazyLock::new(|| {
+    Regex::new(concat!(
+        r"https?://",                          // url scheme
+        r"([-a-zA-Z0-9@:%._\+~#=]{2,256}\.)+", // one or more subdomains
+        r"[a-zA-Z]{2,63}",                     // root domain
+        r"\b([-a-zA-Z0-9@:%_\+.~#?&/=]*)"      // optional query or url fragments
+    ))
+    .expect("failed to build regex")
+});
+
+fn find_raw_urls(
+    cx: &DocContext<'_>,
+    text: &str,
+    range: Range<usize>,
+    f: &impl Fn(&DocContext<'_>, &str, &str, Range<usize>),
+) {
+    trace!("looking for raw urls in {}", text);
+    // For now, we only check "full" URLs (meaning, starting with "http://" or "https://").
+    for match_ in URL_REGEX.find_iter(text) {
+        let url = match_.as_str();
+        let url_range = match_.range();
+        f(
+            cx,
+            "this URL is not a hyperlink",
+            url,
+            Range { start: range.start + url_range.start, end: range.start + url_range.end },
+        );
+    }
+}
diff --git a/src/librustdoc/passes/lint/check_code_block_syntax.rs b/src/librustdoc/passes/lint/check_code_block_syntax.rs
new file mode 100644 (file)
index 0000000..5aa4f23
--- /dev/null
@@ -0,0 +1,170 @@
+//! Validates syntax inside Rust code blocks (\`\`\`rust).
+use rustc_data_structures::sync::{Lock, Lrc};
+use rustc_errors::{
+    emitter::Emitter,
+    translation::{to_fluent_args, Translate},
+    Applicability, Diagnostic, Handler, LazyFallbackBundle,
+};
+use rustc_parse::parse_stream_from_source_str;
+use rustc_session::parse::ParseSess;
+use rustc_span::hygiene::{AstPass, ExpnData, ExpnKind, LocalExpnId};
+use rustc_span::source_map::{FilePathMapping, SourceMap};
+use rustc_span::{FileName, InnerSpan, DUMMY_SP};
+
+use crate::clean;
+use crate::core::DocContext;
+use crate::html::markdown::{self, RustCodeBlock};
+use crate::passes::source_span_for_markdown_range;
+
+pub(crate) fn visit_item(cx: &DocContext<'_>, item: &clean::Item) {
+    if let Some(dox) = &item.attrs.collapsed_doc_value() {
+        let sp = item.attr_span(cx.tcx);
+        let extra =
+            crate::html::markdown::ExtraInfo::new_did(cx.tcx, item.item_id.expect_def_id(), sp);
+        for code_block in markdown::rust_code_blocks(dox, &extra) {
+            check_rust_syntax(cx, item, dox, code_block);
+        }
+    }
+}
+
+fn check_rust_syntax(
+    cx: &DocContext<'_>,
+    item: &clean::Item,
+    dox: &str,
+    code_block: RustCodeBlock,
+) {
+    let buffer = Lrc::new(Lock::new(Buffer::default()));
+    let fallback_bundle =
+        rustc_errors::fallback_fluent_bundle(rustc_errors::DEFAULT_LOCALE_RESOURCES, false);
+    let emitter = BufferEmitter { buffer: Lrc::clone(&buffer), fallback_bundle };
+
+    let sm = Lrc::new(SourceMap::new(FilePathMapping::empty()));
+    let handler = Handler::with_emitter(false, None, Box::new(emitter));
+    let source = dox[code_block.code].to_owned();
+    let sess = ParseSess::with_span_handler(handler, sm);
+
+    let edition = code_block.lang_string.edition.unwrap_or_else(|| cx.tcx.sess.edition());
+    let expn_data =
+        ExpnData::default(ExpnKind::AstPass(AstPass::TestHarness), DUMMY_SP, edition, None, None);
+    let expn_id = cx.tcx.with_stable_hashing_context(|hcx| LocalExpnId::fresh(expn_data, hcx));
+    let span = DUMMY_SP.fresh_expansion(expn_id);
+
+    let is_empty = rustc_driver::catch_fatal_errors(|| {
+        parse_stream_from_source_str(
+            FileName::Custom(String::from("doctest")),
+            source,
+            &sess,
+            Some(span),
+        )
+        .is_empty()
+    })
+    .unwrap_or(false);
+    let buffer = buffer.borrow();
+
+    if !buffer.has_errors && !is_empty {
+        // No errors in a non-empty program.
+        return;
+    }
+
+    let Some(local_id) = item.item_id.as_def_id().and_then(|x| x.as_local())
+        else {
+            // We don't need to check the syntax for other crates so returning
+            // without doing anything should not be a problem.
+            return;
+        };
+
+    let hir_id = cx.tcx.hir().local_def_id_to_hir_id(local_id);
+    let empty_block = code_block.lang_string == Default::default() && code_block.is_fenced;
+    let is_ignore = code_block.lang_string.ignore != markdown::Ignore::None;
+
+    // The span and whether it is precise or not.
+    let (sp, precise_span) =
+        match source_span_for_markdown_range(cx.tcx, dox, &code_block.range, &item.attrs) {
+            Some(sp) => (sp, true),
+            None => (item.attr_span(cx.tcx), false),
+        };
+
+    let msg = if buffer.has_errors {
+        "could not parse code block as Rust code"
+    } else {
+        "Rust code block is empty"
+    };
+
+    // Finally build and emit the completed diagnostic.
+    // All points of divergence have been handled earlier so this can be
+    // done the same way whether the span is precise or not.
+    cx.tcx.struct_span_lint_hir(crate::lint::INVALID_RUST_CODEBLOCKS, hir_id, sp, msg, |lint| {
+        let explanation = if is_ignore {
+            "`ignore` code blocks require valid Rust code for syntax highlighting; \
+                    mark blocks that do not contain Rust code as text"
+        } else {
+            "mark blocks that do not contain Rust code as text"
+        };
+
+        if precise_span {
+            if is_ignore {
+                // giving an accurate suggestion is hard because `ignore` might not have come first in the list.
+                // just give a `help` instead.
+                lint.span_help(
+                    sp.from_inner(InnerSpan::new(0, 3)),
+                    &format!("{}: ```text", explanation),
+                );
+            } else if empty_block {
+                lint.span_suggestion(
+                    sp.from_inner(InnerSpan::new(0, 3)).shrink_to_hi(),
+                    explanation,
+                    "text",
+                    Applicability::MachineApplicable,
+                );
+            }
+        } else if empty_block || is_ignore {
+            lint.help(&format!("{}: ```text", explanation));
+        }
+
+        // FIXME(#67563): Provide more context for these errors by displaying the spans inline.
+        for message in buffer.messages.iter() {
+            lint.note(message);
+        }
+
+        lint
+    });
+}
+
+#[derive(Default)]
+struct Buffer {
+    messages: Vec<String>,
+    has_errors: bool,
+}
+
+struct BufferEmitter {
+    buffer: Lrc<Lock<Buffer>>,
+    fallback_bundle: LazyFallbackBundle,
+}
+
+impl Translate for BufferEmitter {
+    fn fluent_bundle(&self) -> Option<&Lrc<rustc_errors::FluentBundle>> {
+        None
+    }
+
+    fn fallback_fluent_bundle(&self) -> &rustc_errors::FluentBundle {
+        &**self.fallback_bundle
+    }
+}
+
+impl Emitter for BufferEmitter {
+    fn emit_diagnostic(&mut self, diag: &Diagnostic) {
+        let mut buffer = self.buffer.borrow_mut();
+
+        let fluent_args = to_fluent_args(diag.args());
+        let translated_main_message = self.translate_message(&diag.message[0].0, &fluent_args);
+
+        buffer.messages.push(format!("error from rustc: {}", translated_main_message));
+        if diag.is_error() {
+            buffer.has_errors = true;
+        }
+    }
+
+    fn source_map(&self) -> Option<&Lrc<SourceMap>> {
+        None
+    }
+}
diff --git a/src/librustdoc/passes/lint/html_tags.rs b/src/librustdoc/passes/lint/html_tags.rs
new file mode 100644 (file)
index 0000000..070c0aa
--- /dev/null
@@ -0,0 +1,407 @@
+//! Detects invalid HTML (like an unclosed `<span>`) in doc comments.
+use crate::clean::*;
+use crate::core::DocContext;
+use crate::html::markdown::main_body_opts;
+use crate::passes::source_span_for_markdown_range;
+
+use pulldown_cmark::{BrokenLink, Event, LinkType, Parser, Tag};
+
+use std::iter::Peekable;
+use std::ops::Range;
+use std::str::CharIndices;
+
+pub(crate) fn visit_item(cx: &DocContext<'_>, item: &Item) {
+    let tcx = cx.tcx;
+    let Some(hir_id) = DocContext::as_local_hir_id(tcx, item.item_id)
+    // If non-local, no need to check anything.
+    else { return };
+    let dox = item.attrs.collapsed_doc_value().unwrap_or_default();
+    if !dox.is_empty() {
+        let report_diag = |msg: &str, range: &Range<usize>, is_open_tag: bool| {
+            let sp = match source_span_for_markdown_range(tcx, &dox, range, &item.attrs) {
+                Some(sp) => sp,
+                None => item.attr_span(tcx),
+            };
+            tcx.struct_span_lint_hir(crate::lint::INVALID_HTML_TAGS, hir_id, sp, msg, |lint| {
+                use rustc_lint_defs::Applicability;
+                // If a tag looks like `<this>`, it might actually be a generic.
+                // We don't try to detect stuff `<like, this>` because that's not valid HTML,
+                // and we don't try to detect stuff `<like this>` because that's not valid Rust.
+                let mut generics_end = range.end;
+                if let Some(Some(mut generics_start)) = (is_open_tag
+                    && dox[..generics_end].ends_with('>'))
+                .then(|| extract_path_backwards(&dox, range.start))
+                {
+                    while generics_start != 0
+                        && generics_end < dox.len()
+                        && dox.as_bytes()[generics_start - 1] == b'<'
+                        && dox.as_bytes()[generics_end] == b'>'
+                    {
+                        generics_end += 1;
+                        generics_start -= 1;
+                        if let Some(new_start) = extract_path_backwards(&dox, generics_start) {
+                            generics_start = new_start;
+                        }
+                        if let Some(new_end) = extract_path_forward(&dox, generics_end) {
+                            generics_end = new_end;
+                        }
+                    }
+                    if let Some(new_end) = extract_path_forward(&dox, generics_end) {
+                        generics_end = new_end;
+                    }
+                    let generics_sp = match source_span_for_markdown_range(
+                        tcx,
+                        &dox,
+                        &(generics_start..generics_end),
+                        &item.attrs,
+                    ) {
+                        Some(sp) => sp,
+                        None => item.attr_span(tcx),
+                    };
+                    // Sometimes, we only extract part of a path. For example, consider this:
+                    //
+                    //     <[u32] as IntoIter<u32>>::Item
+                    //                       ^^^^^ unclosed HTML tag `u32`
+                    //
+                    // We don't have any code for parsing fully-qualified trait paths.
+                    // In theory, we could add it, but doing it correctly would require
+                    // parsing the entire path grammar, which is problematic because of
+                    // overlap between the path grammar and Markdown.
+                    //
+                    // The example above shows that ambiguity. Is `[u32]` intended to be an
+                    // intra-doc link to the u32 primitive, or is it intended to be a slice?
+                    //
+                    // If the below conditional were removed, we would suggest this, which is
+                    // not what the user probably wants.
+                    //
+                    //     <[u32] as `IntoIter<u32>`>::Item
+                    //
+                    // We know that the user actually wants to wrap the whole thing in a code
+                    // block, but the only reason we know that is because `u32` does not, in
+                    // fact, implement IntoIter. If the example looks like this:
+                    //
+                    //     <[Vec<i32>] as IntoIter<i32>::Item
+                    //
+                    // The ideal fix would be significantly different.
+                    if (generics_start > 0 && dox.as_bytes()[generics_start - 1] == b'<')
+                        || (generics_end < dox.len() && dox.as_bytes()[generics_end] == b'>')
+                    {
+                        return lint;
+                    }
+                    // multipart form is chosen here because ``Vec<i32>`` would be confusing.
+                    lint.multipart_suggestion(
+                        "try marking as source code",
+                        vec![
+                            (generics_sp.shrink_to_lo(), String::from("`")),
+                            (generics_sp.shrink_to_hi(), String::from("`")),
+                        ],
+                        Applicability::MaybeIncorrect,
+                    );
+                }
+
+                lint
+            });
+        };
+
+        let mut tags = Vec::new();
+        let mut is_in_comment = None;
+        let mut in_code_block = false;
+
+        let link_names = item.link_names(&cx.cache);
+
+        let mut replacer = |broken_link: BrokenLink<'_>| {
+            if let Some(link) =
+                link_names.iter().find(|link| *link.original_text == *broken_link.reference)
+            {
+                Some((link.href.as_str().into(), link.new_text.as_str().into()))
+            } else if matches!(
+                &broken_link.link_type,
+                LinkType::Reference | LinkType::ReferenceUnknown
+            ) {
+                // If the link is shaped [like][this], suppress any broken HTML in the [this] part.
+                // The `broken_intra_doc_links` will report typos in there anyway.
+                Some((
+                    broken_link.reference.to_string().into(),
+                    broken_link.reference.to_string().into(),
+                ))
+            } else {
+                None
+            }
+        };
+
+        let p = Parser::new_with_broken_link_callback(&dox, main_body_opts(), Some(&mut replacer))
+            .into_offset_iter();
+
+        for (event, range) in p {
+            match event {
+                Event::Start(Tag::CodeBlock(_)) => in_code_block = true,
+                Event::Html(text) if !in_code_block => {
+                    extract_tags(&mut tags, &text, range, &mut is_in_comment, &report_diag)
+                }
+                Event::End(Tag::CodeBlock(_)) => in_code_block = false,
+                _ => {}
+            }
+        }
+
+        for (tag, range) in tags.iter().filter(|(t, _)| {
+            let t = t.to_lowercase();
+            !ALLOWED_UNCLOSED.contains(&t.as_str())
+        }) {
+            report_diag(&format!("unclosed HTML tag `{}`", tag), range, true);
+        }
+
+        if let Some(range) = is_in_comment {
+            report_diag("Unclosed HTML comment", &range, false);
+        }
+    }
+}
+
+const ALLOWED_UNCLOSED: &[&str] = &[
+    "area", "base", "br", "col", "embed", "hr", "img", "input", "keygen", "link", "meta", "param",
+    "source", "track", "wbr",
+];
+
+fn drop_tag(
+    tags: &mut Vec<(String, Range<usize>)>,
+    tag_name: String,
+    range: Range<usize>,
+    f: &impl Fn(&str, &Range<usize>, bool),
+) {
+    let tag_name_low = tag_name.to_lowercase();
+    if let Some(pos) = tags.iter().rposition(|(t, _)| t.to_lowercase() == tag_name_low) {
+        // If the tag is nested inside a "<script>" or a "<style>" tag, no warning should
+        // be emitted.
+        let should_not_warn = tags.iter().take(pos + 1).any(|(at, _)| {
+            let at = at.to_lowercase();
+            at == "script" || at == "style"
+        });
+        for (last_tag_name, last_tag_span) in tags.drain(pos + 1..) {
+            if should_not_warn {
+                continue;
+            }
+            let last_tag_name_low = last_tag_name.to_lowercase();
+            if ALLOWED_UNCLOSED.contains(&last_tag_name_low.as_str()) {
+                continue;
+            }
+            // `tags` is used as a queue, meaning that everything after `pos` is included inside it.
+            // So `<h2><h3></h2>` will look like `["h2", "h3"]`. So when closing `h2`, we will still
+            // have `h3`, meaning the tag wasn't closed as it should have.
+            f(&format!("unclosed HTML tag `{}`", last_tag_name), &last_tag_span, true);
+        }
+        // Remove the `tag_name` that was originally closed
+        tags.pop();
+    } else {
+        // It can happen for example in this case: `<h2></script></h2>` (the `h2` tag isn't required
+        // but it helps for the visualization).
+        f(&format!("unopened HTML tag `{}`", tag_name), &range, false);
+    }
+}
+
+fn extract_path_backwards(text: &str, end_pos: usize) -> Option<usize> {
+    use rustc_lexer::{is_id_continue, is_id_start};
+    let mut current_pos = end_pos;
+    loop {
+        if current_pos >= 2 && text[..current_pos].ends_with("::") {
+            current_pos -= 2;
+        }
+        let new_pos = text[..current_pos]
+            .char_indices()
+            .rev()
+            .take_while(|(_, c)| is_id_start(*c) || is_id_continue(*c))
+            .reduce(|_accum, item| item)
+            .and_then(|(new_pos, c)| is_id_start(c).then_some(new_pos));
+        if let Some(new_pos) = new_pos {
+            if current_pos != new_pos {
+                current_pos = new_pos;
+                continue;
+            }
+        }
+        break;
+    }
+    if current_pos == end_pos { None } else { Some(current_pos) }
+}
+
+fn extract_path_forward(text: &str, start_pos: usize) -> Option<usize> {
+    use rustc_lexer::{is_id_continue, is_id_start};
+    let mut current_pos = start_pos;
+    loop {
+        if current_pos < text.len() && text[current_pos..].starts_with("::") {
+            current_pos += 2;
+        } else {
+            break;
+        }
+        let mut chars = text[current_pos..].chars();
+        if let Some(c) = chars.next() {
+            if is_id_start(c) {
+                current_pos += c.len_utf8();
+            } else {
+                break;
+            }
+        }
+        while let Some(c) = chars.next() {
+            if is_id_continue(c) {
+                current_pos += c.len_utf8();
+            } else {
+                break;
+            }
+        }
+    }
+    if current_pos == start_pos { None } else { Some(current_pos) }
+}
+
+fn is_valid_for_html_tag_name(c: char, is_empty: bool) -> bool {
+    // https://spec.commonmark.org/0.30/#raw-html
+    //
+    // > A tag name consists of an ASCII letter followed by zero or more ASCII letters, digits, or
+    // > hyphens (-).
+    c.is_ascii_alphabetic() || !is_empty && (c == '-' || c.is_ascii_digit())
+}
+
+fn extract_html_tag(
+    tags: &mut Vec<(String, Range<usize>)>,
+    text: &str,
+    range: &Range<usize>,
+    start_pos: usize,
+    iter: &mut Peekable<CharIndices<'_>>,
+    f: &impl Fn(&str, &Range<usize>, bool),
+) {
+    let mut tag_name = String::new();
+    let mut is_closing = false;
+    let mut prev_pos = start_pos;
+
+    loop {
+        let (pos, c) = match iter.peek() {
+            Some((pos, c)) => (*pos, *c),
+            // In case we reached the of the doc comment, we want to check that it's an
+            // unclosed HTML tag. For example "/// <h3".
+            None => (prev_pos, '\0'),
+        };
+        prev_pos = pos;
+        // Checking if this is a closing tag (like `</a>` for `<a>`).
+        if c == '/' && tag_name.is_empty() {
+            is_closing = true;
+        } else if is_valid_for_html_tag_name(c, tag_name.is_empty()) {
+            tag_name.push(c);
+        } else {
+            if !tag_name.is_empty() {
+                let mut r = Range { start: range.start + start_pos, end: range.start + pos };
+                if c == '>' {
+                    // In case we have a tag without attribute, we can consider the span to
+                    // refer to it fully.
+                    r.end += 1;
+                }
+                if is_closing {
+                    // In case we have "</div >" or even "</div         >".
+                    if c != '>' {
+                        if !c.is_whitespace() {
+                            // It seems like it's not a valid HTML tag.
+                            break;
+                        }
+                        let mut found = false;
+                        for (new_pos, c) in text[pos..].char_indices() {
+                            if !c.is_whitespace() {
+                                if c == '>' {
+                                    r.end = range.start + new_pos + 1;
+                                    found = true;
+                                }
+                                break;
+                            }
+                        }
+                        if !found {
+                            break;
+                        }
+                    }
+                    drop_tag(tags, tag_name, r, f);
+                } else {
+                    let mut is_self_closing = false;
+                    let mut quote_pos = None;
+                    if c != '>' {
+                        let mut quote = None;
+                        let mut after_eq = false;
+                        for (i, c) in text[pos..].char_indices() {
+                            if !c.is_whitespace() {
+                                if let Some(q) = quote {
+                                    if c == q {
+                                        quote = None;
+                                        quote_pos = None;
+                                        after_eq = false;
+                                    }
+                                } else if c == '>' {
+                                    break;
+                                } else if c == '/' && !after_eq {
+                                    is_self_closing = true;
+                                } else {
+                                    if is_self_closing {
+                                        is_self_closing = false;
+                                    }
+                                    if (c == '"' || c == '\'') && after_eq {
+                                        quote = Some(c);
+                                        quote_pos = Some(pos + i);
+                                    } else if c == '=' {
+                                        after_eq = true;
+                                    }
+                                }
+                            } else if quote.is_none() {
+                                after_eq = false;
+                            }
+                        }
+                    }
+                    if let Some(quote_pos) = quote_pos {
+                        let qr = Range { start: quote_pos, end: quote_pos };
+                        f(
+                            &format!("unclosed quoted HTML attribute on tag `{}`", tag_name),
+                            &qr,
+                            false,
+                        );
+                    }
+                    if is_self_closing {
+                        // https://html.spec.whatwg.org/#parse-error-non-void-html-element-start-tag-with-trailing-solidus
+                        let valid = ALLOWED_UNCLOSED.contains(&&tag_name[..])
+                            || tags.iter().take(pos + 1).any(|(at, _)| {
+                                let at = at.to_lowercase();
+                                at == "svg" || at == "math"
+                            });
+                        if !valid {
+                            f(&format!("invalid self-closing HTML tag `{}`", tag_name), &r, false);
+                        }
+                    } else {
+                        tags.push((tag_name, r));
+                    }
+                }
+            }
+            break;
+        }
+        iter.next();
+    }
+}
+
+fn extract_tags(
+    tags: &mut Vec<(String, Range<usize>)>,
+    text: &str,
+    range: Range<usize>,
+    is_in_comment: &mut Option<Range<usize>>,
+    f: &impl Fn(&str, &Range<usize>, bool),
+) {
+    let mut iter = text.char_indices().peekable();
+
+    while let Some((start_pos, c)) = iter.next() {
+        if is_in_comment.is_some() {
+            if text[start_pos..].starts_with("-->") {
+                *is_in_comment = None;
+            }
+        } else if c == '<' {
+            if text[start_pos..].starts_with("<!--") {
+                // We skip the "!--" part. (Once `advance_by` is stable, might be nice to use it!)
+                iter.next();
+                iter.next();
+                iter.next();
+                *is_in_comment = Some(Range {
+                    start: range.start + start_pos,
+                    end: range.start + start_pos + 3,
+                });
+            } else {
+                extract_html_tag(tags, text, &range, start_pos, &mut iter, f);
+            }
+        }
+    }
+}
index f81b38ea39574f1c08ccad79ac4c550d85222d8e..634e70ec97a0dbad224ca2595f7197d7eb7300f6 100644 (file)
@@ -12,9 +12,6 @@
 mod stripper;
 pub(crate) use stripper::*;
 
-mod bare_urls;
-pub(crate) use self::bare_urls::CHECK_BARE_URLS;
-
 mod strip_hidden;
 pub(crate) use self::strip_hidden::STRIP_HIDDEN;
 
 mod collect_trait_impls;
 pub(crate) use self::collect_trait_impls::COLLECT_TRAIT_IMPLS;
 
-mod check_code_block_syntax;
-pub(crate) use self::check_code_block_syntax::CHECK_CODE_BLOCK_SYNTAX;
-
 mod calculate_doc_coverage;
 pub(crate) use self::calculate_doc_coverage::CALCULATE_DOC_COVERAGE;
 
-mod html_tags;
-pub(crate) use self::html_tags::CHECK_INVALID_HTML_TAGS;
+mod lint;
+pub(crate) use self::lint::RUN_LINTS;
 
 /// A single pass over the cleaned documentation.
 ///
@@ -82,11 +76,9 @@ pub(crate) enum Condition {
     STRIP_PRIV_IMPORTS,
     PROPAGATE_DOC_CFG,
     COLLECT_INTRA_DOC_LINKS,
-    CHECK_CODE_BLOCK_SYNTAX,
     COLLECT_TRAIT_IMPLS,
     CALCULATE_DOC_COVERAGE,
-    CHECK_INVALID_HTML_TAGS,
-    CHECK_BARE_URLS,
+    RUN_LINTS,
 ];
 
 /// The list of passes run by default.
@@ -97,10 +89,8 @@ pub(crate) enum Condition {
     ConditionalPass::new(STRIP_PRIVATE, WhenNotDocumentPrivate),
     ConditionalPass::new(STRIP_PRIV_IMPORTS, WhenDocumentPrivate),
     ConditionalPass::always(COLLECT_INTRA_DOC_LINKS),
-    ConditionalPass::always(CHECK_CODE_BLOCK_SYNTAX),
-    ConditionalPass::always(CHECK_INVALID_HTML_TAGS),
     ConditionalPass::always(PROPAGATE_DOC_CFG),
-    ConditionalPass::always(CHECK_BARE_URLS),
+    ConditionalPass::always(RUN_LINTS),
 ];
 
 /// The list of default passes run when `--doc-coverage` is passed to rustdoc.
index dfa6ba38b883b11559e2a8b03f97a90817aa7852..f2ee99cd9d4943e1e1a576d1c26a52d1f8881541 100644 (file)
@@ -110,6 +110,7 @@ pub(crate) struct CallData {
     pub(crate) url: String,
     pub(crate) display_name: String,
     pub(crate) edition: Edition,
+    pub(crate) is_bin: bool,
 }
 
 pub(crate) type FnCallLocations = FxHashMap<PathBuf, CallData>;
@@ -122,6 +123,7 @@ struct FindCalls<'a, 'tcx> {
     cx: Context<'tcx>,
     target_crates: Vec<CrateNum>,
     calls: &'a mut AllCallLocations,
+    bin_crate: bool,
 }
 
 impl<'a, 'tcx> Visitor<'tcx> for FindCalls<'a, 'tcx>
@@ -245,7 +247,9 @@ fn visit_expr(&mut self, ex: &'tcx hir::Expr<'tcx>) {
                 let mk_call_data = || {
                     let display_name = file_path.display().to_string();
                     let edition = call_span.edition();
-                    CallData { locations: Vec::new(), url, display_name, edition }
+                    let is_bin = self.bin_crate;
+
+                    CallData { locations: Vec::new(), url, display_name, edition, is_bin }
                 };
 
                 let fn_key = tcx.def_path_hash(*def_id);
@@ -274,6 +278,7 @@ pub(crate) fn run(
     cache: formats::cache::Cache,
     tcx: TyCtxt<'_>,
     options: ScrapeExamplesOptions,
+    bin_crate: bool,
 ) -> interface::Result<()> {
     let inner = move || -> Result<(), String> {
         // Generates source files for examples
@@ -300,7 +305,8 @@ pub(crate) fn run(
 
         // Run call-finder on all items
         let mut calls = FxHashMap::default();
-        let mut finder = FindCalls { calls: &mut calls, tcx, map: tcx.hir(), cx, target_crates };
+        let mut finder =
+            FindCalls { calls: &mut calls, tcx, map: tcx.hir(), cx, target_crates, bin_crate };
         tcx.hir().visit_all_item_likes_in_crate(&mut finder);
 
         // The visitor might have found a type error, which we need to
index c788b9f4093fea7721b838118443e16a71708ee1..22068ebe041c729ca87e33470255f9e40c22bb3b 100644 (file)
@@ -301,39 +301,40 @@ fn visit_item(
             hir::ItemKind::GlobalAsm(..) => {}
             hir::ItemKind::Use(_, hir::UseKind::ListStem) => {}
             hir::ItemKind::Use(path, kind) => {
-                let is_glob = kind == hir::UseKind::Glob;
-
-                // Struct and variant constructors and proc macro stubs always show up alongside
-                // their definitions, we've already processed them so just discard these.
-                if let Res::Def(DefKind::Ctor(..), _) | Res::SelfCtor(..) = path.res {
-                    return;
-                }
-
-                let attrs = self.cx.tcx.hir().attrs(item.hir_id());
+                for &res in &path.res {
+                    // Struct and variant constructors and proc macro stubs always show up alongside
+                    // their definitions, we've already processed them so just discard these.
+                    if let Res::Def(DefKind::Ctor(..), _) | Res::SelfCtor(..) = res {
+                        continue;
+                    }
 
-                // If there was a private module in the current path then don't bother inlining
-                // anything as it will probably be stripped anyway.
-                if is_pub && self.inside_public_path {
-                    let please_inline = attrs.iter().any(|item| match item.meta_item_list() {
-                        Some(ref list) if item.has_name(sym::doc) => {
-                            list.iter().any(|i| i.has_name(sym::inline))
+                    let attrs = self.cx.tcx.hir().attrs(item.hir_id());
+
+                    // If there was a private module in the current path then don't bother inlining
+                    // anything as it will probably be stripped anyway.
+                    if is_pub && self.inside_public_path {
+                        let please_inline = attrs.iter().any(|item| match item.meta_item_list() {
+                            Some(ref list) if item.has_name(sym::doc) => {
+                                list.iter().any(|i| i.has_name(sym::inline))
+                            }
+                            _ => false,
+                        });
+                        let is_glob = kind == hir::UseKind::Glob;
+                        let ident = if is_glob { None } else { Some(name) };
+                        if self.maybe_inline_local(
+                            item.hir_id(),
+                            res,
+                            ident,
+                            is_glob,
+                            om,
+                            please_inline,
+                        ) {
+                            continue;
                         }
-                        _ => false,
-                    });
-                    let ident = if is_glob { None } else { Some(name) };
-                    if self.maybe_inline_local(
-                        item.hir_id(),
-                        path.res,
-                        ident,
-                        is_glob,
-                        om,
-                        please_inline,
-                    ) {
-                        return;
                     }
-                }
 
-                om.items.push((item, renamed, parent_id))
+                    om.items.push((item, renamed, parent_id))
+                }
             }
             hir::ItemKind::Macro(ref macro_def, _) => {
                 // `#[macro_export] macro_rules!` items are handled separately in `visit()`,
index a1232c451fc27173f8718e05d174b2503ca0b607..3dfd4d93fa013e1c0578d3ceac5c8f4ebba4b6ec 160000 (submodule)
@@ -1 +1 @@
-Subproject commit a1232c451fc27173f8718e05d174b2503ca0b607
+Subproject commit 3dfd4d93fa013e1c0578d3ceac5c8f4ebba4b6ec
diff --git a/src/test/assembly/asm/aarch64-el2vmsa.rs b/src/test/assembly/asm/aarch64-el2vmsa.rs
new file mode 100644 (file)
index 0000000..1908ffb
--- /dev/null
@@ -0,0 +1,37 @@
+// assembly-output: emit-asm
+// compile-flags: --target aarch64-unknown-linux-gnu
+// needs-llvm-components: aarch64
+
+#![feature(no_core, lang_items, rustc_attrs)]
+#![crate_type = "rlib"]
+#![no_core]
+
+#[rustc_builtin_macro]
+macro_rules! asm {
+    () => {};
+}
+
+#[lang = "sized"]
+trait Sized {}
+
+// CHECK-LABEL: ttbr0_el2:
+#[no_mangle]
+pub fn ttbr0_el2() {
+    // CHECK: //APP
+    // CHECK-NEXT: msr TTBR0_EL2, x0
+    // CHECK-NEXT: //NO_APP
+    unsafe {
+        asm!("msr ttbr0_el2, x0");
+    }
+}
+
+// CHECK-LABEL: vttbr_el2:
+#[no_mangle]
+pub fn vttbr_el2() {
+    // CHECK: //APP
+    // CHECK-NEXT: msr VTTBR_EL2, x0
+    // CHECK-NEXT: //NO_APP
+    unsafe {
+        asm!("msr vttbr_el2, x0");
+    }
+}
index 6a898b2974a65f40fb3eba2dc11cc205c457a5fe..6309dd420ffa4d5c8c42915fdbfd6a9e86b43924 100644 (file)
@@ -44,12 +44,16 @@ pub struct Franta {
     tst_use(arg.b);
     tst_use(arg.c);
     tst_use(arg.d);
+    tail_call_avoidance_fn();
 }
 
 extern "C" {
     fn opaque_callee(arg: Franta, intarg: i32);
     fn tst_use(arg: f32);
     fn clobber();
+    // This exists so that post-https://reviews.llvm.org/D138741 LLVM doesn't
+    // tail-call away some of our assertions.
+    fn tail_call_avoidance_fn();
 }
 
 #[no_mangle]
@@ -62,4 +66,5 @@ pub struct Franta {
     // CHECK: call opaque_callee
     // CHECK: mov     3, %o2
     opaque_callee(Franta { a: 1.0, b: 2.0, c: 3.0, d: 4.0 }, 3);
+    tail_call_avoidance_fn();
 }
index 3ea3a24bfae11daf42e148a4ed0b061a0be51f97..b90ef104ce72a3fd2c2a28744066d545c42d6b34 100644 (file)
@@ -8,6 +8,8 @@
 // On riscv the closure is another function, placed before fn foo so CHECK can't
 // find it
 // ignore-riscv64 FIXME
+// On s390x the closure is also in another function
+// ignore-s390x FIXME
 
 #![crate_type = "lib"]
 #![feature(c_unwind)]
index efab189fd7b8f9876b46aea2bd050bb21b6dca77..44f1b408d21b8f0ede3c3ceb48cec463f614e142 100644 (file)
@@ -34,11 +34,8 @@ pub enum Enum1 {
 
 // CHECK: define i8 @match1{{.*}}
 // CHECK-NEXT: start:
-// CHECK-NEXT: %1 = icmp ugt i8 %0, 1
-// CHECK-NEXT: %2 = zext i8 %0 to i64
-// CHECK-NEXT: %3 = add nsw i64 %2, -1
-// CHECK-NEXT: %_2 = select i1 %1, i64 %3, i64 0
-// CHECK-NEXT: switch i64 %_2, label {{.*}} [
+// CHECK-NEXT: %1 = {{.*}}call i8 @llvm.usub.sat.i8(i8 %0, i8 1)
+// CHECK-NEXT: switch i8 %1, label {{.*}} [
 #[no_mangle]
 pub fn match1(e: Enum1) -> u8 {
     use Enum1::*;
diff --git a/src/test/codegen/issue-105386-ub-in-debuginfo.rs b/src/test/codegen/issue-105386-ub-in-debuginfo.rs
new file mode 100644 (file)
index 0000000..d54ac9e
--- /dev/null
@@ -0,0 +1,22 @@
+// compile-flags: --crate-type=lib -O -Cdebuginfo=2 -Cno-prepopulate-passes
+// min-llvm-version: 15.0 # this test uses opaque pointer notation
+#![feature(stmt_expr_attributes)]
+
+pub struct S([usize; 8]);
+
+#[no_mangle]
+pub fn outer_function(x: S, y: S) -> usize {
+    (#[inline(always)]|| {
+        let _z = x;
+        y.0[0]
+    })()
+}
+
+// Check that we do not attempt to load from the spilled arg before it is assigned to
+// when generating debuginfo.
+// CHECK-LABEL: @outer_function
+// CHECK: [[spill:%.*]] = alloca %"[closure@{{.*.rs}}:9:23: 9:25]"
+// CHECK-NOT: [[ptr_tmp:%.*]] = getelementptr inbounds %"[closure@{{.*.rs}}:9:23: 9:25]", ptr [[spill]]
+// CHECK-NOT: [[load:%.*]] = load ptr, ptr
+// CHECK: call void @llvm.lifetime.start{{.*}}({{.*}}, ptr [[spill]])
+// CHECK: call void @llvm.memcpy{{.*}}(ptr {{align .*}} [[spill]], ptr {{align .*}} %x
diff --git a/src/test/codegen/naked-nocoverage.rs b/src/test/codegen/naked-nocoverage.rs
new file mode 100644 (file)
index 0000000..91a6260
--- /dev/null
@@ -0,0 +1,19 @@
+// Checks that naked functions are not instrumented by -Cinstrument-coverage.
+// Regression test for issue #105170.
+//
+// needs-asm-support
+// needs-profiler-support
+// compile-flags: -Cinstrument-coverage
+#![crate_type = "lib"]
+#![feature(naked_functions)]
+use std::arch::asm;
+
+#[naked]
+#[no_mangle]
+pub unsafe extern "C" fn f() {
+    // CHECK:       define void @f()
+    // CHECK-NEXT:  start:
+    // CHECK-NEXT:    call void asm
+    // CHECK-NEXT:    unreachable
+    asm!("", options(noreturn));
+}
diff --git a/src/test/codegen/pgo-counter-bias.rs b/src/test/codegen/pgo-counter-bias.rs
new file mode 100644 (file)
index 0000000..28caa7f
--- /dev/null
@@ -0,0 +1,10 @@
+// Test that __llvm_profile_counter_bias does not get internalized by lto.
+
+// ignore-macos -runtime-counter-relocation not honored on Mach-O
+// compile-flags: -Cprofile-generate -Cllvm-args=-runtime-counter-relocation -Clto=fat
+// needs-profiler-support
+// no-prefer-dynamic
+
+// CHECK: @__llvm_profile_counter_bias = {{.*}}global
+
+pub fn main() {}
index 9bef743ddcb414127a0b7cae1e26a12ffdab1f1c..78ebbccfce1950fe372e1dc74f9f9723d6f92cdf 100644 (file)
@@ -12,7 +12,7 @@
 include!("aux_mod.rs");
 
 // Here we check that the expansion of the file!() macro is mapped.
-// CHECK: @alloc2 = private unnamed_addr constant <{ [34 x i8] }> <{ [34 x i8] c"/the/src/remap_path_prefix/main.rs" }>, align 1
+// CHECK: @alloc2 = private unnamed_addr constant <{ [34 x i8] }> <{ [34 x i8] c"/the/src/remap_path_prefix/main.rs" }>
 pub static FILE_PATH: &'static str = file!();
 
 fn main() {
index 9d18c5f03c665151ce0757988ba88588376e2996..f733de12b3537097f21a0f4a3cea52185d7c18d0 100644 (file)
@@ -8,6 +8,7 @@
 // ignore-powerpc
 // ignore-powerpc64
 // ignore-riscv64 see codegen/riscv-abi
+// ignore-s390x
 // ignore-windows
 // See repr-transparent.rs
 
index c68ba8460cb1409d91fc4508aef19da815a50e58..4f2313ce47a979be33140172948c254831e8b538 100644 (file)
@@ -2,6 +2,7 @@
 
 // ignore-riscv64 riscv64 has an i128 type used with test_Vector
 // see codegen/riscv-abi for riscv functiona call tests
+// ignore-s390x s390x with default march passes vector types per reference
 
 #![crate_type="lib"]
 #![feature(repr_simd, transparent_unions)]
diff --git a/src/test/codegen/sanitizer-kcfi-add-kcfi-flag.rs b/src/test/codegen/sanitizer-kcfi-add-kcfi-flag.rs
new file mode 100644 (file)
index 0000000..c2eb852
--- /dev/null
@@ -0,0 +1,11 @@
+// Verifies that "kcfi" module flag is added.
+//
+// needs-sanitizer-kcfi
+// compile-flags: -Ctarget-feature=-crt-static -Zsanitizer=kcfi
+
+#![crate_type="lib"]
+
+pub fn foo() {
+}
+
+// CHECK: !{{[0-9]+}} = !{i32 4, !"kcfi", i32 1}
diff --git a/src/test/codegen/sanitizer-kcfi-emit-kcfi-operand-bundle-itanium-cxx-abi.rs b/src/test/codegen/sanitizer-kcfi-emit-kcfi-operand-bundle-itanium-cxx-abi.rs
new file mode 100644 (file)
index 0000000..0afd972
--- /dev/null
@@ -0,0 +1,47 @@
+// Verifies that KCFI type metadata for functions are emitted.
+//
+// revisions: aarch64 x86_64
+// [aarch64] compile-flags: --target aarch64-unknown-none
+// [aarch64] needs-llvm-components: aarch64
+// [x86_64] compile-flags: --target x86_64-unknown-none
+// [x86_64] needs-llvm-components:
+// compile-flags: -Cno-prepopulate-passes -Zsanitizer=kcfi
+
+#![crate_type="lib"]
+#![feature(no_core, lang_items)]
+#![no_core]
+
+#[lang="sized"]
+trait Sized { }
+#[lang="copy"]
+trait Copy { }
+
+impl Copy for i32 {}
+
+pub fn foo(f: fn(i32) -> i32, arg: i32) -> i32 {
+    // CHECK-LABEL: define{{.*}}foo
+    // FIXME(rcvalle): Change <unknown kind #36> to !kcfi_type when Rust is updated to LLVM 16
+    // CHECK-SAME: {{.*}}!<unknown kind #36> ![[TYPE1:[0-9]+]]
+    // CHECK: call i32 %f(i32 %arg){{.*}}[ "kcfi"(i32 -1666898348) ]
+    f(arg)
+}
+
+pub fn bar(f: fn(i32, i32) -> i32, arg1: i32, arg2: i32) -> i32 {
+    // CHECK-LABEL: define{{.*}}bar
+    // FIXME(rcvalle): Change <unknown kind #36> to !kcfi_type when Rust is updated to LLVM 16
+    // CHECK-SAME: {{.*}}!<unknown kind #36> ![[TYPE2:[0-9]+]]
+    // CHECK: call i32 %f(i32 %arg1, i32 %arg2){{.*}}[ "kcfi"(i32 -1789026986) ]
+    f(arg1, arg2)
+}
+
+pub fn baz(f: fn(i32, i32, i32) -> i32, arg1: i32, arg2: i32, arg3: i32) -> i32 {
+    // CHECK-LABEL: define{{.*}}baz
+    // FIXME(rcvalle): Change <unknown kind #36> to !kcfi_type when Rust is updated to LLVM 16
+    // CHECK-SAME: {{.*}}!<unknown kind #36> ![[TYPE3:[0-9]+]]
+    // CHECK: call i32 %f(i32 %arg1, i32 %arg2, i32 %arg3){{.*}}[ "kcfi"(i32 1248878270) ]
+    f(arg1, arg2, arg3)
+}
+
+// CHECK: ![[TYPE1]] = !{i32 653723426}
+// CHECK: ![[TYPE2]] = !{i32 412174924}
+// CHECK: ![[TYPE3]] = !{i32 -636668840}
index 4c07740b3560420eb3cc38acab4643e3ec60cf70..98a6761f8abbb3261bf660427bc97392f6891431 100644 (file)
@@ -14,7 +14,7 @@ pub struct PartiallyUninit {
 
 // CHECK: [[FULLY_UNINIT:@[0-9]+]] = private unnamed_addr constant <{ [10 x i8] }> undef
 
-// CHECK: [[PARTIALLY_UNINIT:@[0-9]+]] = private unnamed_addr constant <{ [4 x i8], [12 x i8] }> <{ [4 x i8] c"\EF\BE\AD\DE", [12 x i8] undef }>, align 4
+// CHECK: [[PARTIALLY_UNINIT:@[0-9]+]] = private unnamed_addr constant <{ [4 x i8], [12 x i8] }> <{ [4 x i8] c"{{\\EF\\BE\\AD\\DE|\\DE\\AD\\BE\\EF}}", [12 x i8] undef }>, align 4
 
 // This shouldn't contain undef, since it contains more chunks
 // than the default value of uninit_const_chunk_threshold.
index 57e298625f9a086c1e19dac1904153824bafc34f..9780332d8bf18813d2658000920e92e91f7e8824 100644 (file)
@@ -8,7 +8,7 @@
   
       bb0: {
           _2 = discriminant(_1);           // scope 0 at $DIR/76803_regression.rs:+1:11: +1:12
-          switchInt(move _2) -> [0_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/76803_regression.rs:+1:5: +1:12
+          switchInt(move _2) -> [0: bb2, otherwise: bb1]; // scope 0 at $DIR/76803_regression.rs:+1:5: +1:12
       }
   
       bb1: {
index 9c5a9fa9abb0e617036579f0fb741ee04a890e93..0af5d82d31540debb60c201f5201332058981578 100644 (file)
@@ -14,7 +14,7 @@
 -         _2 = Ne(move _3, const true);    // scope 0 at $DIR/bool_compare.rs:+1:8: +1:17
 +         _2 = Not(move _3);               // scope 0 at $DIR/bool_compare.rs:+1:8: +1:17
           StorageDead(_3);                 // scope 0 at $DIR/bool_compare.rs:+1:16: +1:17
-          switchInt(move _2) -> [false: bb2, otherwise: bb1]; // scope 0 at $DIR/bool_compare.rs:+1:8: +1:17
+          switchInt(move _2) -> [0: bb2, otherwise: bb1]; // scope 0 at $DIR/bool_compare.rs:+1:8: +1:17
       }
   
       bb1: {
index 58c52c4b7d7ff36bfc528cf4d28031226194a406..f5d1febd991cd5aef3f2964c80372d1966e8fd5b 100644 (file)
@@ -14,7 +14,7 @@
 -         _2 = Ne(const true, move _3);    // scope 0 at $DIR/bool_compare.rs:+1:8: +1:17
 +         _2 = Not(move _3);               // scope 0 at $DIR/bool_compare.rs:+1:8: +1:17
           StorageDead(_3);                 // scope 0 at $DIR/bool_compare.rs:+1:16: +1:17
-          switchInt(move _2) -> [false: bb2, otherwise: bb1]; // scope 0 at $DIR/bool_compare.rs:+1:8: +1:17
+          switchInt(move _2) -> [0: bb2, otherwise: bb1]; // scope 0 at $DIR/bool_compare.rs:+1:8: +1:17
       }
   
       bb1: {
index 676428c95c1bf01d89e674f8017c66358bcbcec0..e7432adac7d9d366e75830c62b45d8f9ae3ff569 100644 (file)
@@ -14,7 +14,7 @@
 -         _2 = Eq(move _3, const false);   // scope 0 at $DIR/bool_compare.rs:+1:8: +1:18
 +         _2 = Not(move _3);               // scope 0 at $DIR/bool_compare.rs:+1:8: +1:18
           StorageDead(_3);                 // scope 0 at $DIR/bool_compare.rs:+1:17: +1:18
-          switchInt(move _2) -> [false: bb2, otherwise: bb1]; // scope 0 at $DIR/bool_compare.rs:+1:8: +1:18
+          switchInt(move _2) -> [0: bb2, otherwise: bb1]; // scope 0 at $DIR/bool_compare.rs:+1:8: +1:18
       }
   
       bb1: {
index addfcd769a5468327578048b5c8838661877957c..6b3e27772f71c978b4bd06feb76e83cf5d0226a0 100644 (file)
@@ -14,7 +14,7 @@
 -         _2 = Eq(const false, move _3);   // scope 0 at $DIR/bool_compare.rs:+1:8: +1:18
 +         _2 = Not(move _3);               // scope 0 at $DIR/bool_compare.rs:+1:8: +1:18
           StorageDead(_3);                 // scope 0 at $DIR/bool_compare.rs:+1:17: +1:18
-          switchInt(move _2) -> [false: bb2, otherwise: bb1]; // scope 0 at $DIR/bool_compare.rs:+1:8: +1:18
+          switchInt(move _2) -> [0: bb2, otherwise: bb1]; // scope 0 at $DIR/bool_compare.rs:+1:8: +1:18
       }
   
       bb1: {
index 0ebd840cf2d5cc02db12cc2fe1250bec9caba143..628a33f1020a5f625d333a536f9c795061a24d79 100644 (file)
@@ -27,7 +27,7 @@ fn main() -> () {
         StorageLive(_5);                 // scope 1 at $DIR/issue_101867.rs:+2:14: +2:15
         FakeRead(ForMatchedPlace(None), _1); // scope 1 at $DIR/issue_101867.rs:+2:19: +2:20
         _6 = discriminant(_1);           // scope 1 at $DIR/issue_101867.rs:+2:19: +2:20
-        switchInt(move _6) -> [1_isize: bb4, otherwise: bb3]; // scope 1 at $DIR/issue_101867.rs:+2:9: +2:16
+        switchInt(move _6) -> [1: bb4, otherwise: bb3]; // scope 1 at $DIR/issue_101867.rs:+2:9: +2:16
     }
 
     bb1: {
index 9182bcaa21fa6afa92f1056c1698d95db2e1def3..de5e4c0f6ed48dc33a50002ebb2bb8edc0b9f33c 100644 (file)
@@ -25,7 +25,7 @@ fn main() -> () {
         StorageLive(_3);                 // scope 0 at $DIR/issue_49232.rs:+3:19: +3:23
         _3 = const true;                 // scope 0 at $DIR/issue_49232.rs:+3:19: +3:23
         FakeRead(ForMatchedPlace(None), _3); // scope 0 at $DIR/issue_49232.rs:+3:19: +3:23
-        switchInt(_3) -> [false: bb3, otherwise: bb4]; // scope 0 at $DIR/issue_49232.rs:+3:13: +3:23
+        switchInt(_3) -> [0: bb3, otherwise: bb4]; // scope 0 at $DIR/issue_49232.rs:+3:13: +3:23
     }
 
     bb3: {
index 9a190c3d60ea49607f9e76a3ceb031bb659e18f8..cb36bc64da69597809b68fdb2dac704c6ff7accc 100644 (file)
@@ -28,7 +28,7 @@ fn full_tested_match() -> () {
         _2 = Option::<i32>::Some(const 42_i32); // scope 0 at $DIR/match_false_edges.rs:+1:19: +1:27
         FakeRead(ForMatchedPlace(None), _2); // scope 0 at $DIR/match_false_edges.rs:+1:19: +1:27
         _3 = discriminant(_2);           // scope 0 at $DIR/match_false_edges.rs:+1:19: +1:27
-        switchInt(move _3) -> [0_isize: bb1, 1_isize: bb2, otherwise: bb4]; // scope 0 at $DIR/match_false_edges.rs:+1:13: +1:27
+        switchInt(move _3) -> [0: bb1, 1: bb2, otherwise: bb4]; // scope 0 at $DIR/match_false_edges.rs:+1:13: +1:27
     }
 
     bb1: {
@@ -60,7 +60,7 @@ fn full_tested_match() -> () {
     }
 
     bb6: {
-        switchInt(move _7) -> [false: bb8, otherwise: bb7]; // scope 0 at $DIR/match_false_edges.rs:+2:20: +2:27
+        switchInt(move _7) -> [0: bb8, otherwise: bb7]; // scope 0 at $DIR/match_false_edges.rs:+2:20: +2:27
     }
 
     bb7: {
index 1c9953e7efc11ec538638eeed0355ad50f1a1024..7f8755faac6cf78f146d55ec9a291ced6ae387dc 100644 (file)
@@ -28,7 +28,7 @@ fn full_tested_match2() -> () {
         _2 = Option::<i32>::Some(const 42_i32); // scope 0 at $DIR/match_false_edges.rs:+1:19: +1:27
         FakeRead(ForMatchedPlace(None), _2); // scope 0 at $DIR/match_false_edges.rs:+1:19: +1:27
         _3 = discriminant(_2);           // scope 0 at $DIR/match_false_edges.rs:+1:19: +1:27
-        switchInt(move _3) -> [0_isize: bb1, 1_isize: bb2, otherwise: bb4]; // scope 0 at $DIR/match_false_edges.rs:+1:13: +1:27
+        switchInt(move _3) -> [0: bb1, 1: bb2, otherwise: bb4]; // scope 0 at $DIR/match_false_edges.rs:+1:13: +1:27
     }
 
     bb1: {
@@ -66,7 +66,7 @@ fn full_tested_match2() -> () {
     }
 
     bb6: {
-        switchInt(move _7) -> [false: bb8, otherwise: bb7]; // scope 0 at $DIR/match_false_edges.rs:+2:20: +2:27
+        switchInt(move _7) -> [0: bb8, otherwise: bb7]; // scope 0 at $DIR/match_false_edges.rs:+2:20: +2:27
     }
 
     bb7: {
index 08c67d39d78074f393be1f3963fa60d8be60db3e..e8b93f4371ecbadb05ce0c559300d80d3de25c31 100644 (file)
@@ -39,7 +39,7 @@ fn main() -> () {
         _2 = Option::<i32>::Some(const 1_i32); // scope 0 at $DIR/match_false_edges.rs:+1:19: +1:26
         FakeRead(ForMatchedPlace(None), _2); // scope 0 at $DIR/match_false_edges.rs:+1:19: +1:26
         _4 = discriminant(_2);           // scope 0 at $DIR/match_false_edges.rs:+1:19: +1:26
-        switchInt(move _4) -> [1_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/match_false_edges.rs:+1:13: +1:26
+        switchInt(move _4) -> [1: bb2, otherwise: bb1]; // scope 0 at $DIR/match_false_edges.rs:+1:13: +1:26
     }
 
     bb1: {
@@ -56,7 +56,7 @@ fn main() -> () {
 
     bb4: {
         _3 = discriminant(_2);           // scope 0 at $DIR/match_false_edges.rs:+1:19: +1:26
-        switchInt(move _3) -> [1_isize: bb6, otherwise: bb5]; // scope 0 at $DIR/match_false_edges.rs:+1:13: +1:26
+        switchInt(move _3) -> [1: bb6, otherwise: bb5]; // scope 0 at $DIR/match_false_edges.rs:+1:13: +1:26
     }
 
     bb5: {
@@ -87,7 +87,7 @@ fn main() -> () {
     }
 
     bb9: {
-        switchInt(move _8) -> [false: bb11, otherwise: bb10]; // scope 0 at $DIR/match_false_edges.rs:+2:21: +2:28
+        switchInt(move _8) -> [0: bb11, otherwise: bb10]; // scope 0 at $DIR/match_false_edges.rs:+2:21: +2:28
     }
 
     bb10: {
@@ -134,7 +134,7 @@ fn main() -> () {
     }
 
     bb15: {
-        switchInt(move _12) -> [false: bb17, otherwise: bb16]; // scope 0 at $DIR/match_false_edges.rs:+4:20: +4:29
+        switchInt(move _12) -> [0: bb17, otherwise: bb16]; // scope 0 at $DIR/match_false_edges.rs:+4:20: +4:29
     }
 
     bb16: {
index a4516026c3b47b748f11661169ba7260ee504f1a..aa2fd46320e137fa281c34109ea89ed27f5187b7 100644 (file)
@@ -6,7 +6,7 @@ fn match_bool(_1: bool) -> usize {
 
     bb0: {
         FakeRead(ForMatchedPlace(None), _1); // scope 0 at $DIR/simple_match.rs:+1:11: +1:12
-        switchInt(_1) -> [false: bb2, otherwise: bb1]; // scope 0 at $DIR/simple_match.rs:+1:5: +1:12
+        switchInt(_1) -> [0: bb2, otherwise: bb1]; // scope 0 at $DIR/simple_match.rs:+1:5: +1:12
     }
 
     bb1: {
index fade2d0bc6edf7890e10417738eac10e5a344278..a717d1bbd12f2c2ab965969cdebd33d9fdd30efa 100644 (file)
@@ -11,9 +11,9 @@
       bb0: {
 -         StorageLive(_2);                 // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
 -         _3 = discriminant(_1);           // scope 0 at $DIR/const_goto.rs:+1:17: +1:20
--         switchInt(move _3) -> [1_isize: bb2, 2_isize: bb2, otherwise: bb1]; // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+-         switchInt(move _3) -> [1: bb2, 2: bb2, otherwise: bb1]; // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
 +         _2 = discriminant(_1);           // scope 0 at $DIR/const_goto.rs:+1:17: +1:20
-+         switchInt(move _2) -> [1_isize: bb2, 2_isize: bb2, otherwise: bb1]; // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
++         switchInt(move _2) -> [1: bb2, 2: bb2, otherwise: bb1]; // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
       }
   
       bb1: {
@@ -29,7 +29,7 @@
 -     }
 - 
 -     bb3: {
--         switchInt(move _2) -> [false: bb5, otherwise: bb4]; // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+-         switchInt(move _2) -> [0: bb5, otherwise: bb4]; // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
 -     }
 - 
 -     bb4: {
index 623297aeba5062e240963802333e99c46c135f13..24be8c9b86845b8147db55dbfe373cf695a6eebb 100644 (file)
@@ -10,7 +10,7 @@
           StorageLive(_1);                 // scope 0 at $DIR/const_goto_const_eval_fail.rs:+1:11: +6:6
           StorageLive(_2);                 // scope 0 at $DIR/const_goto_const_eval_fail.rs:+2:15: +2:16
           _2 = const A;                    // scope 0 at $DIR/const_goto_const_eval_fail.rs:+2:15: +2:16
-          switchInt(_2) -> [1_i32: bb2, 2_i32: bb2, 3_i32: bb2, otherwise: bb1]; // scope 0 at $DIR/const_goto_const_eval_fail.rs:+2:9: +2:16
+          switchInt(_2) -> [1: bb2, 2: bb2, 3: bb2, otherwise: bb1]; // scope 0 at $DIR/const_goto_const_eval_fail.rs:+2:9: +2:16
       }
   
       bb1: {
       bb2: {
           _1 = const B;                    // scope 0 at $DIR/const_goto_const_eval_fail.rs:+3:26: +3:27
 -         goto -> bb3;                     // scope 0 at $DIR/const_goto_const_eval_fail.rs:+3:26: +3:27
-+         switchInt(_1) -> [false: bb4, otherwise: bb3]; // scope 0 at $DIR/const_goto_const_eval_fail.rs:+1:5: +6:6
++         switchInt(_1) -> [0: bb4, otherwise: bb3]; // scope 0 at $DIR/const_goto_const_eval_fail.rs:+1:5: +6:6
       }
   
       bb3: {
--         switchInt(_1) -> [false: bb5, otherwise: bb4]; // scope 0 at $DIR/const_goto_const_eval_fail.rs:+1:5: +6:6
+-         switchInt(_1) -> [0: bb5, otherwise: bb4]; // scope 0 at $DIR/const_goto_const_eval_fail.rs:+1:5: +6:6
 -     }
 - 
 -     bb4: {
index 81c356cb1db526b0373d8664983d63a44ae428ba..f54577259431da796336b9c52d937c479de6e213 100644 (file)
 -         StorageLive(_5);                 // scope 0 at $DIR/const_goto_storage.rs:+2:21: +2:52
 -         StorageLive(_6);                 // scope 0 at $DIR/const_goto_storage.rs:+2:24: +2:28
 -         _6 = const true;                 // scope 0 at $DIR/const_goto_storage.rs:+2:24: +2:28
--         switchInt(move _6) -> [false: bb2, otherwise: bb1]; // scope 0 at $DIR/const_goto_storage.rs:+2:24: +2:28
+-         switchInt(move _6) -> [0: bb2, otherwise: bb1]; // scope 0 at $DIR/const_goto_storage.rs:+2:24: +2:28
 +         StorageLive(_2);                 // scope 0 at $DIR/const_goto_storage.rs:+2:24: +2:28
 +         _2 = const true;                 // scope 0 at $DIR/const_goto_storage.rs:+2:24: +2:28
-+         switchInt(move _2) -> [false: bb2, otherwise: bb1]; // scope 0 at $DIR/const_goto_storage.rs:+2:24: +2:28
++         switchInt(move _2) -> [0: bb2, otherwise: bb1]; // scope 0 at $DIR/const_goto_storage.rs:+2:24: +2:28
       }
   
       bb1: {
@@ -41,7 +41,7 @@
 - 
 -     bb3: {
 -         StorageDead(_6);                 // scope 0 at $DIR/const_goto_storage.rs:+2:51: +2:52
--         switchInt(move _5) -> [false: bb5, otherwise: bb4]; // scope 0 at $DIR/const_goto_storage.rs:+2:21: +2:52
+-         switchInt(move _5) -> [0: bb5, otherwise: bb4]; // scope 0 at $DIR/const_goto_storage.rs:+2:21: +2:52
 -     }
 - 
 -     bb4: {
@@ -56,7 +56,7 @@
 - 
 -     bb6: {
 -         StorageDead(_5);                 // scope 0 at $DIR/const_goto_storage.rs:+2:75: +2:76
--         switchInt(move _4) -> [false: bb8, otherwise: bb7]; // scope 0 at $DIR/const_goto_storage.rs:+2:18: +2:76
+-         switchInt(move _4) -> [0: bb8, otherwise: bb7]; // scope 0 at $DIR/const_goto_storage.rs:+2:18: +2:76
 -     }
 - 
 -     bb7: {
@@ -70,7 +70,7 @@
 -     }
 - 
 -     bb9: {
--         switchInt(move _3) -> [false: bb11, otherwise: bb10]; // scope 0 at $DIR/const_goto_storage.rs:+2:15: +6:10
+-         switchInt(move _3) -> [0: bb11, otherwise: bb10]; // scope 0 at $DIR/const_goto_storage.rs:+2:15: +6:10
 -     }
 - 
 -     bb10: {
index 8b3b9d0a4c1bbd87457eeb1322931cb4a80705a3..147670f8a915c4681eb853556097617f52ebf063 100644 (file)
@@ -9,8 +9,8 @@
       bb0: {
           StorageLive(_1);                 // scope 0 at $DIR/control_flow_simplification.rs:+1:8: +1:21
           _1 = const _;                    // scope 0 at $DIR/control_flow_simplification.rs:+1:8: +1:21
--         switchInt(move _1) -> [false: bb2, otherwise: bb1]; // scope 0 at $DIR/control_flow_simplification.rs:+1:8: +1:21
-+         switchInt(const false) -> [false: bb2, otherwise: bb1]; // scope 0 at $DIR/control_flow_simplification.rs:+1:8: +1:21
+-         switchInt(move _1) -> [0: bb2, otherwise: bb1]; // scope 0 at $DIR/control_flow_simplification.rs:+1:8: +1:21
++         switchInt(const false) -> [0: bb2, otherwise: bb1]; // scope 0 at $DIR/control_flow_simplification.rs:+1:8: +1:21
       }
   
       bb1: {
index 6b29bb59c40dacc56c3161cb4bdfe71a6e0d6098..b4dccecc67265e74d5191fa6930acf8b1ee8e307 100644 (file)
           ((_3 as Some).0: bool) = const true; // scope 2 at $DIR/discriminant.rs:+1:34: +1:44
           discriminant(_3) = 1;            // scope 2 at $DIR/discriminant.rs:+1:34: +1:44
 -         _4 = discriminant(_3);           // scope 2 at $DIR/discriminant.rs:+1:21: +1:31
--         switchInt(move _4) -> [1_isize: bb1, otherwise: bb3]; // scope 2 at $DIR/discriminant.rs:+1:21: +1:31
+-         switchInt(move _4) -> [1: bb1, otherwise: bb3]; // scope 2 at $DIR/discriminant.rs:+1:21: +1:31
 +         _4 = const 1_isize;              // scope 2 at $DIR/discriminant.rs:+1:21: +1:31
-+         switchInt(const 1_isize) -> [1_isize: bb1, otherwise: bb3]; // scope 2 at $DIR/discriminant.rs:+1:21: +1:31
++         switchInt(const 1_isize) -> [1: bb1, otherwise: bb3]; // scope 2 at $DIR/discriminant.rs:+1:21: +1:31
       }
   
       bb1: {
-          switchInt(((_3 as Some).0: bool)) -> [false: bb3, otherwise: bb2]; // scope 2 at $DIR/discriminant.rs:+1:21: +1:31
+          switchInt(((_3 as Some).0: bool)) -> [0: bb3, otherwise: bb2]; // scope 2 at $DIR/discriminant.rs:+1:21: +1:31
       }
   
       bb2: {
index 6b29bb59c40dacc56c3161cb4bdfe71a6e0d6098..b4dccecc67265e74d5191fa6930acf8b1ee8e307 100644 (file)
           ((_3 as Some).0: bool) = const true; // scope 2 at $DIR/discriminant.rs:+1:34: +1:44
           discriminant(_3) = 1;            // scope 2 at $DIR/discriminant.rs:+1:34: +1:44
 -         _4 = discriminant(_3);           // scope 2 at $DIR/discriminant.rs:+1:21: +1:31
--         switchInt(move _4) -> [1_isize: bb1, otherwise: bb3]; // scope 2 at $DIR/discriminant.rs:+1:21: +1:31
+-         switchInt(move _4) -> [1: bb1, otherwise: bb3]; // scope 2 at $DIR/discriminant.rs:+1:21: +1:31
 +         _4 = const 1_isize;              // scope 2 at $DIR/discriminant.rs:+1:21: +1:31
-+         switchInt(const 1_isize) -> [1_isize: bb1, otherwise: bb3]; // scope 2 at $DIR/discriminant.rs:+1:21: +1:31
++         switchInt(const 1_isize) -> [1: bb1, otherwise: bb3]; // scope 2 at $DIR/discriminant.rs:+1:21: +1:31
       }
   
       bb1: {
-          switchInt(((_3 as Some).0: bool)) -> [false: bb3, otherwise: bb2]; // scope 2 at $DIR/discriminant.rs:+1:21: +1:31
+          switchInt(((_3 as Some).0: bool)) -> [0: bb3, otherwise: bb2]; // scope 2 at $DIR/discriminant.rs:+1:21: +1:31
       }
   
       bb2: {
index 9d7c2784d8b2cab9060446aac746879752e33243..ddc1a4493dbbf697a02a4a41f868e8fc83c7e8cb 100644 (file)
@@ -8,8 +8,8 @@
       bb0: {
           StorageLive(_1);                 // scope 0 at $DIR/switch_int.rs:+1:11: +1:12
           _1 = const 1_i32;                // scope 0 at $DIR/switch_int.rs:+1:11: +1:12
--         switchInt(_1) -> [1_i32: bb2, otherwise: bb1]; // scope 0 at $DIR/switch_int.rs:+1:5: +1:12
-+         switchInt(const 1_i32) -> [1_i32: bb2, otherwise: bb1]; // scope 0 at $DIR/switch_int.rs:+1:5: +1:12
+-         switchInt(_1) -> [1: bb2, otherwise: bb1]; // scope 0 at $DIR/switch_int.rs:+1:5: +1:12
++         switchInt(const 1_i32) -> [1: bb2, otherwise: bb1]; // scope 0 at $DIR/switch_int.rs:+1:5: +1:12
       }
   
       bb1: {
index 74f9eafe42061cd0724e94a550eef3aa487dea20..09c47ee6e8309deaa6504a8c0f9d55faefc55223 100644 (file)
@@ -8,7 +8,7 @@
       bb0: {
           StorageLive(_1);                 // scope 0 at $DIR/switch_int.rs:+1:11: +1:12
           _1 = const 1_i32;                // scope 0 at $DIR/switch_int.rs:+1:11: +1:12
--         switchInt(const 1_i32) -> [1_i32: bb2, otherwise: bb1]; // scope 0 at $DIR/switch_int.rs:+1:5: +1:12
+-         switchInt(const 1_i32) -> [1: bb2, otherwise: bb1]; // scope 0 at $DIR/switch_int.rs:+1:5: +1:12
 +         goto -> bb2;                     // scope 0 at $DIR/switch_int.rs:+1:5: +1:12
       }
   
index fd21b14af25f3b8fcd1d3e1e0ef6b85d29e72c25..c4d389b2d764818426147cf1822148f1d089174d 100644 (file)
@@ -7,7 +7,7 @@ digraph Cov_0_3 {
     bcb1__Cov_0_3 [shape="none", label=<<table border="0" cellborder="1" cellspacing="0"><tr><td bgcolor="gray" align="center" colspan="1">bcb1</td></tr><tr><td align="left" balign="left">Expression(bcb0 + bcb3) at 10:5-11:17<br align="left"/>    11:12-11:17: @2.Call: _2 = bar() -&gt; [return: bb3, unwind: bb6]</td></tr><tr><td align="left" balign="left">bb1: FalseUnwind<br align="left"/>bb2: Call</td></tr><tr><td align="left" balign="left">bb3: SwitchInt</td></tr></table>>];
     bcb0__Cov_0_3 [shape="none", label=<<table border="0" cellborder="1" cellspacing="0"><tr><td bgcolor="gray" align="center" colspan="1">bcb0</td></tr><tr><td align="left" balign="left"></td></tr><tr><td align="left" balign="left">Counter(bcb0) at 9:1-9:11<br align="left"/>    </td></tr><tr><td align="left" balign="left">bb0: Goto</td></tr></table>>];
     bcb3__Cov_0_3 -> bcb1__Cov_0_3 [label=<>];
-    bcb1__Cov_0_3 -> bcb3__Cov_0_3 [label=<false>];
+    bcb1__Cov_0_3 -> bcb3__Cov_0_3 [label=<0>];
     bcb1__Cov_0_3 -> bcb2__Cov_0_3 [label=<otherwise>];
     bcb0__Cov_0_3 -> bcb1__Cov_0_3 [label=<>];
 }
index 2ced794e628f0462813e4f0065136af076984464..fce18fae4362f17224dfcc0ed6213575176167c5 100644 (file)
@@ -28,7 +28,7 @@
           discriminant(_1) = 0;            // scope 0 at $DIR/enum.rs:+1:13: +1:21
           StorageLive(_2);                 // scope 1 at $DIR/enum.rs:+2:9: +2:10
           _3 = discriminant(_1);           // scope 1 at $DIR/enum.rs:+2:19: +2:20
-          switchInt(move _3) -> [0_isize: bb3, 1_isize: bb1, otherwise: bb2]; // scope 1 at $DIR/enum.rs:+2:13: +2:20
+          switchInt(move _3) -> [0: bb3, 1: bb1, otherwise: bb2]; // scope 1 at $DIR/enum.rs:+2:13: +2:20
       }
   
       bb1: {
index 26808c70fbf2c42a711020001ff4790f24320c1e..32489b4bd6bfeb57987277e2e1fe14fea90ea0a8 100644 (file)
@@ -42,8 +42,8 @@
 +         _4 = const 1_i32;                // scope 1 at $DIR/if.rs:+2:16: +2:17
 +         _3 = const true;                 // scope 1 at $DIR/if.rs:+2:16: +2:22
           StorageDead(_4);                 // scope 1 at $DIR/if.rs:+2:21: +2:22
--         switchInt(move _3) -> [false: bb2, otherwise: bb1]; // scope 1 at $DIR/if.rs:+2:16: +2:22
-+         switchInt(const true) -> [false: bb2, otherwise: bb1]; // scope 1 at $DIR/if.rs:+2:16: +2:22
+-         switchInt(move _3) -> [0: bb2, otherwise: bb1]; // scope 1 at $DIR/if.rs:+2:16: +2:22
++         switchInt(const true) -> [0: bb2, otherwise: bb1]; // scope 1 at $DIR/if.rs:+2:16: +2:22
       }
   
       bb1: {
@@ -73,8 +73,8 @@
 +         _9 = const 1_i32;                // scope 3 at $DIR/if.rs:+5:16: +5:17
 +         _8 = const true;                 // scope 3 at $DIR/if.rs:+5:16: +5:22
           StorageDead(_9);                 // scope 3 at $DIR/if.rs:+5:21: +5:22
--         switchInt(move _8) -> [false: bb5, otherwise: bb4]; // scope 3 at $DIR/if.rs:+5:16: +5:22
-+         switchInt(const true) -> [false: bb5, otherwise: bb4]; // scope 3 at $DIR/if.rs:+5:16: +5:22
+-         switchInt(move _8) -> [0: bb5, otherwise: bb4]; // scope 3 at $DIR/if.rs:+5:16: +5:22
++         switchInt(const true) -> [0: bb5, otherwise: bb4]; // scope 3 at $DIR/if.rs:+5:16: +5:22
       }
   
       bb4: {
index 881d80f7c032606fa969eddf7adc8d4db00b2e89..5a87884977c39bc3b8aa7f711dc2159561ac4ef8 100644 (file)
@@ -10,8 +10,8 @@
           StorageLive(_1);                 // scope 0 at $DIR/issue_81605.rs:+1:9: +1:33
           StorageLive(_2);                 // scope 0 at $DIR/issue_81605.rs:+1:12: +1:16
           _2 = const true;                 // scope 0 at $DIR/issue_81605.rs:+1:12: +1:16
--         switchInt(move _2) -> [false: bb2, otherwise: bb1]; // scope 0 at $DIR/issue_81605.rs:+1:12: +1:16
-+         switchInt(const true) -> [false: bb2, otherwise: bb1]; // scope 0 at $DIR/issue_81605.rs:+1:12: +1:16
+-         switchInt(move _2) -> [0: bb2, otherwise: bb1]; // scope 0 at $DIR/issue_81605.rs:+1:12: +1:16
++         switchInt(const true) -> [0: bb2, otherwise: bb1]; // scope 0 at $DIR/issue_81605.rs:+1:12: +1:16
       }
   
       bb1: {
index 61d24c3b517fbfd84eb5f0977c7986ff81b839ff..80f8905adc92d93ae714a7b326a16ec22e6f11cd 100644 (file)
@@ -37,8 +37,8 @@
       }
   
       bb2: {
--         switchInt(move _5) -> [false: bb4, otherwise: bb3]; // scope 0 at $DIR/cycle.rs:+3:11: +3:17
-+         switchInt(move _4) -> [false: bb4, otherwise: bb3]; // scope 0 at $DIR/cycle.rs:+3:11: +3:17
+-         switchInt(move _5) -> [0: bb4, otherwise: bb3]; // scope 0 at $DIR/cycle.rs:+3:11: +3:17
++         switchInt(move _4) -> [0: bb4, otherwise: bb3]; // scope 0 at $DIR/cycle.rs:+3:11: +3:17
       }
   
       bb3: {
index fb18089e040f08a47e7a86c5457469059c050df4..210d3849e18a106bb1e76987b5934588e335ba34 100644 (file)
@@ -12,7 +12,7 @@
       bb0: {
           StorageLive(_3);                 // scope 0 at $DIR/deaggregator_test_enum_2.rs:+1:8: +1:9
           _3 = _1;                         // scope 0 at $DIR/deaggregator_test_enum_2.rs:+1:8: +1:9
-          switchInt(move _3) -> [false: bb2, otherwise: bb1]; // scope 0 at $DIR/deaggregator_test_enum_2.rs:+1:8: +1:9
+          switchInt(move _3) -> [0: bb2, otherwise: bb1]; // scope 0 at $DIR/deaggregator_test_enum_2.rs:+1:8: +1:9
       }
   
       bb1: {
index 995611f0e966416fdf9a7b938d2036e27e1c7dc0..3b1f81175cbfcc49148618d7a177f8522b0e7c8b 100644 (file)
           _7 = Len((*_2));                 // scope 0 at $DIR/deduplicate_blocks.rs:+2:9: +2:37
           _8 = const 4_usize;              // scope 0 at $DIR/deduplicate_blocks.rs:+2:9: +2:37
           _9 = Ge(move _7, move _8);       // scope 0 at $DIR/deduplicate_blocks.rs:+2:9: +2:37
-          switchInt(move _9) -> [false: bb6, otherwise: bb2]; // scope 0 at $DIR/deduplicate_blocks.rs:+2:9: +2:37
+          switchInt(move _9) -> [0: bb6, otherwise: bb2]; // scope 0 at $DIR/deduplicate_blocks.rs:+2:9: +2:37
       }
   
       bb2: {
-          switchInt((*_2)[0 of 4]) -> [47_u8: bb3, otherwise: bb6]; // scope 0 at $DIR/deduplicate_blocks.rs:+1:5: +1:23
+          switchInt((*_2)[0 of 4]) -> [47: bb3, otherwise: bb6]; // scope 0 at $DIR/deduplicate_blocks.rs:+1:5: +1:23
       }
   
       bb3: {
-          switchInt((*_2)[1 of 4]) -> [47_u8: bb4, otherwise: bb6]; // scope 0 at $DIR/deduplicate_blocks.rs:+1:5: +1:23
+          switchInt((*_2)[1 of 4]) -> [47: bb4, otherwise: bb6]; // scope 0 at $DIR/deduplicate_blocks.rs:+1:5: +1:23
       }
   
       bb4: {
-          switchInt((*_2)[2 of 4]) -> [47_u8: bb5, otherwise: bb6]; // scope 0 at $DIR/deduplicate_blocks.rs:+1:5: +1:23
+          switchInt((*_2)[2 of 4]) -> [47: bb5, otherwise: bb6]; // scope 0 at $DIR/deduplicate_blocks.rs:+1:5: +1:23
       }
   
       bb5: {
--         switchInt((*_2)[3 of 4]) -> [47_u8: bb11, otherwise: bb6]; // scope 0 at $DIR/deduplicate_blocks.rs:+1:5: +1:23
-+         switchInt((*_2)[3 of 4]) -> [47_u8: bb10, otherwise: bb6]; // scope 0 at $DIR/deduplicate_blocks.rs:+1:5: +1:23
+-         switchInt((*_2)[3 of 4]) -> [47: bb11, otherwise: bb6]; // scope 0 at $DIR/deduplicate_blocks.rs:+1:5: +1:23
++         switchInt((*_2)[3 of 4]) -> [47: bb10, otherwise: bb6]; // scope 0 at $DIR/deduplicate_blocks.rs:+1:5: +1:23
       }
   
       bb6: {
           _4 = Len((*_2));                 // scope 0 at $DIR/deduplicate_blocks.rs:+3:9: +3:31
           _5 = const 3_usize;              // scope 0 at $DIR/deduplicate_blocks.rs:+3:9: +3:31
           _6 = Ge(move _4, move _5);       // scope 0 at $DIR/deduplicate_blocks.rs:+3:9: +3:31
-          switchInt(move _6) -> [false: bb10, otherwise: bb7]; // scope 0 at $DIR/deduplicate_blocks.rs:+3:9: +3:31
+          switchInt(move _6) -> [0: bb10, otherwise: bb7]; // scope 0 at $DIR/deduplicate_blocks.rs:+3:9: +3:31
       }
   
       bb7: {
-          switchInt((*_2)[0 of 3]) -> [47_u8: bb8, otherwise: bb10]; // scope 0 at $DIR/deduplicate_blocks.rs:+1:5: +1:23
+          switchInt((*_2)[0 of 3]) -> [47: bb8, otherwise: bb10]; // scope 0 at $DIR/deduplicate_blocks.rs:+1:5: +1:23
       }
   
       bb8: {
-          switchInt((*_2)[1 of 3]) -> [47_u8: bb9, otherwise: bb10]; // scope 0 at $DIR/deduplicate_blocks.rs:+1:5: +1:23
+          switchInt((*_2)[1 of 3]) -> [47: bb9, otherwise: bb10]; // scope 0 at $DIR/deduplicate_blocks.rs:+1:5: +1:23
       }
   
       bb9: {
--         switchInt((*_2)[2 of 3]) -> [47_u8: bb12, 33_u8: bb13, otherwise: bb10]; // scope 0 at $DIR/deduplicate_blocks.rs:+1:5: +1:23
-+         switchInt((*_2)[2 of 3]) -> [47_u8: bb11, 33_u8: bb11, otherwise: bb10]; // scope 0 at $DIR/deduplicate_blocks.rs:+1:5: +1:23
+-         switchInt((*_2)[2 of 3]) -> [47: bb12, 33: bb13, otherwise: bb10]; // scope 0 at $DIR/deduplicate_blocks.rs:+1:5: +1:23
++         switchInt((*_2)[2 of 3]) -> [47: bb11, 33: bb11, otherwise: bb10]; // scope 0 at $DIR/deduplicate_blocks.rs:+1:5: +1:23
       }
   
       bb10: {
index 5b185082d4d87f839f31e472c7bdb5475b9a934d..9597a0c835fddd26907f92f59533943e9eb7b009 100644 (file)
@@ -17,7 +17,7 @@ fn foo(_1: Option<String>) -> i32 {
         _7 = const false;                // scope 0 at $DIR/string.rs:+1:11: +1:12
         _7 = const true;                 // scope 0 at $DIR/string.rs:+1:11: +1:12
         _5 = discriminant(_1);           // scope 0 at $DIR/string.rs:+1:11: +1:12
-        switchInt(move _5) -> [1_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/string.rs:+1:5: +1:12
+        switchInt(move _5) -> [1: bb2, otherwise: bb1]; // scope 0 at $DIR/string.rs:+1:5: +1:12
     }
 
     bb1: {
@@ -47,7 +47,7 @@ fn foo(_1: Option<String>) -> i32 {
     }
 
     bb4: {
-        switchInt(move _4) -> [false: bb1, otherwise: bb5]; // scope 0 at $DIR/string.rs:+2:14: +2:17
+        switchInt(move _4) -> [0: bb1, otherwise: bb5]; // scope 0 at $DIR/string.rs:+2:14: +2:17
     }
 
     bb5: {
@@ -69,6 +69,6 @@ fn foo(_1: Option<String>) -> i32 {
     }
 
     bb9: {
-        switchInt(_7) -> [false: bb7, otherwise: bb8]; // scope 0 at $DIR/string.rs:+5:1: +5:2
+        switchInt(_7) -> [0: bb7, otherwise: bb8]; // scope 0 at $DIR/string.rs:+5:1: +5:2
     }
 }
index 713d56c383613aad9ab9b9072b75f25252f762fc..fa3eeedc40fffee479371c748617291fe96cd852 100644 (file)
@@ -62,7 +62,7 @@
       bb3: {
           StorageDead(_8);                 // scope 1 at $DIR/derefer_complex_case.rs:+1:25: +1:26
           _10 = discriminant(_7);          // scope 1 at $DIR/derefer_complex_case.rs:+1:17: +1:26
-          switchInt(move _10) -> [0_isize: bb6, 1_isize: bb4, otherwise: bb5]; // scope 1 at $DIR/derefer_complex_case.rs:+1:17: +1:26
+          switchInt(move _10) -> [0: bb6, 1: bb4, otherwise: bb5]; // scope 1 at $DIR/derefer_complex_case.rs:+1:17: +1:26
       }
   
       bb4: {
index 60f7b9d5607b0ae646c83e0b6a652b3711b75f80..ab2388d1323a85cb6f0ab499ef9c1915fa0c6fc3 100644 (file)
           _6 = &_7;                        // scope 2 at $DIR/derefer_terminator_test.rs:+3:18: +3:21
           _5 = &_6;                        // scope 2 at $DIR/derefer_terminator_test.rs:+3:17: +3:21
           _4 = &_5;                        // scope 2 at $DIR/derefer_terminator_test.rs:+3:15: +3:22
--         switchInt((*(*(*(*_4))))) -> [false: bb3, otherwise: bb4]; // scope 2 at $DIR/derefer_terminator_test.rs:+3:5: +3:22
+-         switchInt((*(*(*(*_4))))) -> [0: bb3, otherwise: bb4]; // scope 2 at $DIR/derefer_terminator_test.rs:+3:5: +3:22
 +         _10 = deref_copy (*_4);          // scope 2 at $DIR/derefer_terminator_test.rs:+3:5: +3:22
 +         _11 = deref_copy (*_10);         // scope 2 at $DIR/derefer_terminator_test.rs:+3:5: +3:22
 +         _12 = deref_copy (*_11);         // scope 2 at $DIR/derefer_terminator_test.rs:+3:5: +3:22
-+         switchInt((*_12)) -> [false: bb3, otherwise: bb4]; // scope 2 at $DIR/derefer_terminator_test.rs:+3:5: +3:22
++         switchInt((*_12)) -> [0: bb3, otherwise: bb4]; // scope 2 at $DIR/derefer_terminator_test.rs:+3:5: +3:22
       }
   
       bb3: {
index 5fa7013d5ca762daba0f0a1ce1933be91a4b6497..9c729663265e087f5507fb2b769c4d0acbc81eaf 100644 (file)
@@ -37,7 +37,7 @@
       }
   
       bb2: {
-          switchInt(move _3) -> [false: bb4, otherwise: bb3]; // scope 1 at $DIR/branch.rs:+3:16: +3:22
+          switchInt(move _3) -> [0: bb4, otherwise: bb3]; // scope 1 at $DIR/branch.rs:+3:16: +3:22
       }
   
       bb3: {
index 89d8106ae3ce7394079b1f33df0ca5e804fcebff..98a02ee38dd1769b2e6bd0cf5bcac0f74b14b2eb 100644 (file)
           StorageDead(_5);                 // scope 0 at $DIR/early_otherwise_branch.rs:+1:16: +1:17
           StorageDead(_4);                 // scope 0 at $DIR/early_otherwise_branch.rs:+1:16: +1:17
           _7 = discriminant((_3.0: std::option::Option<u32>)); // scope 0 at $DIR/early_otherwise_branch.rs:+1:11: +1:17
--         switchInt(move _7) -> [1_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch.rs:+1:5: +1:17
+-         switchInt(move _7) -> [1: bb2, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch.rs:+1:5: +1:17
 +         StorageLive(_10);                // scope 0 at $DIR/early_otherwise_branch.rs:+1:5: +1:17
 +         _10 = discriminant((_3.1: std::option::Option<u32>)); // scope 0 at $DIR/early_otherwise_branch.rs:+1:5: +1:17
 +         StorageLive(_11);                // scope 0 at $DIR/early_otherwise_branch.rs:+1:5: +1:17
 +         _11 = Ne(_7, move _10);          // scope 0 at $DIR/early_otherwise_branch.rs:+1:5: +1:17
 +         StorageDead(_10);                // scope 0 at $DIR/early_otherwise_branch.rs:+1:5: +1:17
-+         switchInt(move _11) -> [false: bb4, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch.rs:+1:5: +1:17
++         switchInt(move _11) -> [0: bb4, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch.rs:+1:5: +1:17
       }
   
       bb1: {
@@ -49,7 +49,7 @@
   
       bb2: {
 -         _6 = discriminant((_3.1: std::option::Option<u32>)); // scope 0 at $DIR/early_otherwise_branch.rs:+1:11: +1:17
--         switchInt(move _6) -> [1_isize: bb3, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch.rs:+1:5: +1:17
+-         switchInt(move _6) -> [1: bb3, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch.rs:+1:5: +1:17
 -     }
 - 
 -     bb3: {
@@ -72,7 +72,7 @@
 + 
 +     bb4: {
 +         StorageDead(_11);                // scope 0 at $DIR/early_otherwise_branch.rs:+1:5: +1:17
-+         switchInt(_7) -> [1_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch.rs:+1:5: +1:17
++         switchInt(_7) -> [1: bb2, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch.rs:+1:5: +1:17
       }
   }
   
index 1a9efa930036c40e0583477d27e55f5a2b3c1067..aa75c44b809a90543004dbd7f49c9ec9d949953c 100644 (file)
           StorageDead(_5);                 // scope 0 at $DIR/early_otherwise_branch.rs:+1:16: +1:17
           StorageDead(_4);                 // scope 0 at $DIR/early_otherwise_branch.rs:+1:16: +1:17
           _8 = discriminant((_3.0: std::option::Option<u32>)); // scope 0 at $DIR/early_otherwise_branch.rs:+1:11: +1:17
--         switchInt(move _8) -> [0_isize: bb1, 1_isize: bb3, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch.rs:+1:5: +1:17
+-         switchInt(move _8) -> [0: bb1, 1: bb3, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch.rs:+1:5: +1:17
 +         StorageLive(_11);                // scope 0 at $DIR/early_otherwise_branch.rs:+1:5: +1:17
 +         _11 = discriminant((_3.1: std::option::Option<u32>)); // scope 0 at $DIR/early_otherwise_branch.rs:+1:5: +1:17
 +         StorageLive(_12);                // scope 0 at $DIR/early_otherwise_branch.rs:+1:5: +1:17
 +         _12 = Ne(_8, move _11);          // scope 0 at $DIR/early_otherwise_branch.rs:+1:5: +1:17
 +         StorageDead(_11);                // scope 0 at $DIR/early_otherwise_branch.rs:+1:5: +1:17
-+         switchInt(move _12) -> [false: bb5, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch.rs:+1:5: +1:17
++         switchInt(move _12) -> [0: bb5, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch.rs:+1:5: +1:17
       }
   
       bb1: {
 -         _6 = discriminant((_3.1: std::option::Option<u32>)); // scope 0 at $DIR/early_otherwise_branch.rs:+1:11: +1:17
--         switchInt(move _6) -> [0_isize: bb5, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch.rs:+1:5: +1:17
+-         switchInt(move _6) -> [0: bb5, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch.rs:+1:5: +1:17
 -     }
 - 
 -     bb2: {
@@ -55,7 +55,7 @@
   
 -     bb3: {
 -         _7 = discriminant((_3.1: std::option::Option<u32>)); // scope 0 at $DIR/early_otherwise_branch.rs:+1:11: +1:17
--         switchInt(move _7) -> [1_isize: bb4, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch.rs:+1:5: +1:17
+-         switchInt(move _7) -> [1: bb4, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch.rs:+1:5: +1:17
 -     }
 - 
 -     bb4: {
@@ -86,7 +86,7 @@
 + 
 +     bb5: {
 +         StorageDead(_12);                // scope 0 at $DIR/early_otherwise_branch.rs:+1:5: +1:17
-+         switchInt(_8) -> [0_isize: bb3, 1_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch.rs:+1:5: +1:17
++         switchInt(_8) -> [0: bb3, 1: bb2, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch.rs:+1:5: +1:17
       }
   }
   
index 309a72ae58b68d19fd25dad179090f67508f318e..cea6ff7cd05e07bd02d4a2c46194cb30969f9908 100644 (file)
           StorageDead(_5);                 // scope 0 at $DIR/early_otherwise_branch.rs:+1:16: +1:17
           StorageDead(_4);                 // scope 0 at $DIR/early_otherwise_branch.rs:+1:16: +1:17
           _7 = discriminant((_3.0: std::option::Option<u32>)); // scope 0 at $DIR/early_otherwise_branch.rs:+1:11: +1:17
--         switchInt(move _7) -> [1_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch.rs:+1:5: +1:17
+-         switchInt(move _7) -> [1: bb2, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch.rs:+1:5: +1:17
 +         StorageLive(_10);                // scope 0 at $DIR/early_otherwise_branch.rs:+1:5: +1:17
 +         _10 = discriminant((_3.1: std::option::Option<bool>)); // scope 0 at $DIR/early_otherwise_branch.rs:+1:5: +1:17
 +         StorageLive(_11);                // scope 0 at $DIR/early_otherwise_branch.rs:+1:5: +1:17
 +         _11 = Ne(_7, move _10);          // scope 0 at $DIR/early_otherwise_branch.rs:+1:5: +1:17
 +         StorageDead(_10);                // scope 0 at $DIR/early_otherwise_branch.rs:+1:5: +1:17
-+         switchInt(move _11) -> [false: bb4, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch.rs:+1:5: +1:17
++         switchInt(move _11) -> [0: bb4, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch.rs:+1:5: +1:17
       }
   
       bb1: {
@@ -49,7 +49,7 @@
   
       bb2: {
 -         _6 = discriminant((_3.1: std::option::Option<bool>)); // scope 0 at $DIR/early_otherwise_branch.rs:+1:11: +1:17
--         switchInt(move _6) -> [1_isize: bb3, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch.rs:+1:5: +1:17
+-         switchInt(move _6) -> [1: bb3, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch.rs:+1:5: +1:17
 -     }
 - 
 -     bb3: {
@@ -72,7 +72,7 @@
 + 
 +     bb4: {
 +         StorageDead(_11);                // scope 0 at $DIR/early_otherwise_branch.rs:+1:5: +1:17
-+         switchInt(_7) -> [1_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch.rs:+1:5: +1:17
++         switchInt(_7) -> [1: bb2, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch.rs:+1:5: +1:17
       }
   }
   
index 9574f32f7f06bd2c28b7d683a936add26f1f5ef7..b90d70ce43aa0ca0d884663a1a775d85a3a3edf6 100644 (file)
           StorageDead(_6);                 // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:+1:19: +1:20
           StorageDead(_5);                 // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:+1:19: +1:20
           _10 = discriminant((_4.0: std::option::Option<u32>)); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:+1:11: +1:20
--         switchInt(move _10) -> [1_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:+1:5: +1:20
+-         switchInt(move _10) -> [1: bb2, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:+1:5: +1:20
 +         StorageLive(_14);                // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:+1:5: +1:20
 +         _14 = discriminant((_4.1: std::option::Option<u32>)); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:+1:5: +1:20
 +         StorageLive(_15);                // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:+1:5: +1:20
 +         _15 = Ne(_10, move _14);         // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:+1:5: +1:20
 +         StorageDead(_14);                // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:+1:5: +1:20
-+         switchInt(move _15) -> [false: bb5, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:+1:5: +1:20
++         switchInt(move _15) -> [0: bb5, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:+1:5: +1:20
       }
   
       bb1: {
   
       bb2: {
 -         _9 = discriminant((_4.1: std::option::Option<u32>)); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:+1:11: +1:20
--         switchInt(move _9) -> [1_isize: bb3, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:+1:5: +1:20
+-         switchInt(move _9) -> [1: bb3, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:+1:5: +1:20
 -     }
 - 
 -     bb3: {
           _8 = discriminant((_4.2: std::option::Option<u32>)); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:+1:11: +1:20
--         switchInt(move _8) -> [1_isize: bb4, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:+1:5: +1:20
-+         switchInt(move _8) -> [1_isize: bb3, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:+1:5: +1:20
+-         switchInt(move _8) -> [1: bb4, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:+1:5: +1:20
++         switchInt(move _8) -> [1: bb3, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:+1:5: +1:20
       }
   
 -     bb4: {
@@ -94,7 +94,7 @@
 + 
 +     bb5: {
 +         StorageDead(_15);                // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:+1:5: +1:20
-+         switchInt(_10) -> [1_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:+1:5: +1:20
++         switchInt(_10) -> [1: bb2, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:+1:5: +1:20
       }
   }
   
index 6bc025bb5b204897dc703bc1ddfa995e634377de..9edd1a39f45f9b050f4a50d1d1c5875461e45ffe 100644 (file)
           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: bb2]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:8: +5:24
+          switchInt(move _11) -> [0: bb1, 1: bb3, 2: bb4, 3: bb5, otherwise: bb2]; // 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
+          switchInt(move _7) -> [0: bb6, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:8: +5:24
       }
   
       bb2: {
       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
+          switchInt(move _8) -> [1: 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
+          switchInt(move _9) -> [2: 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
+          switchInt(move _10) -> [3: bb9, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:8: +5:24
       }
   
       bb6: {
index 321f57951b465309ffebc42d4c86b0d7dab64451..82d8b2fc5a463a740edb395c2c44968a2269f016 100644 (file)
           StorageDead(_5);                 // scope 0 at $DIR/early_otherwise_branch_noopt.rs:+1:16: +1:17
           StorageDead(_4);                 // scope 0 at $DIR/early_otherwise_branch_noopt.rs:+1:16: +1:17
           _8 = discriminant((_3.0: std::option::Option<u32>)); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:+1:11: +1:17
-          switchInt(move _8) -> [0_isize: bb1, 1_isize: bb4, otherwise: bb3]; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:+1:5: +1:17
+          switchInt(move _8) -> [0: bb1, 1: bb4, otherwise: bb3]; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:+1:5: +1:17
       }
   
       bb1: {
           _6 = discriminant((_3.1: std::option::Option<u32>)); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:+1:11: +1:17
-          switchInt(move _6) -> [0_isize: bb2, 1_isize: bb7, otherwise: bb3]; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:+1:5: +1:17
+          switchInt(move _6) -> [0: bb2, 1: bb7, otherwise: bb3]; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:+1:5: +1:17
       }
   
       bb2: {
@@ -57,7 +57,7 @@
   
       bb4: {
           _7 = discriminant((_3.1: std::option::Option<u32>)); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:+1:11: +1:17
-          switchInt(move _7) -> [0_isize: bb6, 1_isize: bb5, otherwise: bb3]; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:+1:5: +1:17
+          switchInt(move _7) -> [0: bb6, 1: bb5, otherwise: bb3]; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:+1:5: +1:17
       }
   
       bb5: {
index 8b556acb2c4520a2382270a677f56e4218062923..a3fa2529b1868cb8a113059fb620c811a71b2633 100644 (file)
@@ -14,7 +14,7 @@
   
       bb0: {
           _3 = discriminant(_1);           // scope 0 at $DIR/early_otherwise_branch_soundness.rs:+1:11: +1:12
-          switchInt(move _3) -> [1_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch_soundness.rs:+1:5: +1:12
+          switchInt(move _3) -> [1: bb2, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch_soundness.rs:+1:5: +1:12
       }
   
       bb1: {
@@ -24,7 +24,7 @@
   
       bb2: {
           _4 = discriminant((*_2));        // scope 0 at $DIR/early_otherwise_branch_soundness.rs:+3:26: +3:28
-          switchInt(move _4) -> [1_isize: bb4, otherwise: bb3]; // scope 0 at $DIR/early_otherwise_branch_soundness.rs:+3:20: +3:28
+          switchInt(move _4) -> [1: bb4, otherwise: bb3]; // scope 0 at $DIR/early_otherwise_branch_soundness.rs:+3:20: +3:28
       }
   
       bb3: {
index 659aed18f0436370ad71c3d48de54dbb09988a31..6d0224b547f4fe2036ac730d6e5b289ac1627328 100644 (file)
   
       bb0: {
           _3 = discriminant((*_1));        // scope 1 at $DIR/early_otherwise_branch_soundness.rs:+1:12: +1:31
-          switchInt(move _3) -> [1_isize: bb1, otherwise: bb3]; // scope 1 at $DIR/early_otherwise_branch_soundness.rs:+1:12: +1:31
+          switchInt(move _3) -> [1: bb1, otherwise: bb3]; // scope 1 at $DIR/early_otherwise_branch_soundness.rs:+1:12: +1:31
       }
   
       bb1: {
           _4 = deref_copy (((*_1) as Some).0: &E<'_>); // scope 1 at $DIR/early_otherwise_branch_soundness.rs:+1:12: +1:31
           _2 = discriminant((*_4));        // scope 1 at $DIR/early_otherwise_branch_soundness.rs:+1:12: +1:31
-          switchInt(move _2) -> [1_isize: bb2, otherwise: bb3]; // scope 1 at $DIR/early_otherwise_branch_soundness.rs:+1:12: +1:31
+          switchInt(move _2) -> [1: bb2, otherwise: bb3]; // scope 1 at $DIR/early_otherwise_branch_soundness.rs:+1:12: +1:31
       }
   
       bb2: {
index 89982308e71619408943b34bf1e16f0fab8943ad..8b542a7c19d63ae1f189275a83713485de931875 100644 (file)
@@ -14,7 +14,7 @@
 -         _2 = Eq(move _3, const true);    // scope 0 at $DIR/equal_true.rs:+1:8: +1:17
 +         _2 = move _3;                    // scope 0 at $DIR/equal_true.rs:+1:8: +1:17
           StorageDead(_3);                 // scope 0 at $DIR/equal_true.rs:+1:16: +1:17
-          switchInt(move _2) -> [false: bb2, otherwise: bb1]; // scope 0 at $DIR/equal_true.rs:+1:8: +1:17
+          switchInt(move _2) -> [0: bb2, otherwise: bb1]; // scope 0 at $DIR/equal_true.rs:+1:8: +1:17
       }
   
       bb1: {
index 08481777ed494e81293c32dce0e85aa77ba168ca..ab955049965ada01ad44a6744c897e80d9f3fcdf 100644 (file)
@@ -19,7 +19,7 @@ fn match_tuple(_1: (u32, bool, Option<i32>, u32)) -> u32 {
 
     bb0: {
         FakeRead(ForMatchedPlace(None), _1); // scope 0 at $DIR/exponential_or.rs:+1:11: +1:12
-        switchInt((_1.0: u32)) -> [1_u32: bb2, 4_u32: bb2, otherwise: bb1]; // scope 0 at $DIR/exponential_or.rs:+2:15: +2:20
+        switchInt((_1.0: u32)) -> [1: bb2, 4: bb2, otherwise: bb1]; // scope 0 at $DIR/exponential_or.rs:+2:15: +2:20
     }
 
     bb1: {
@@ -29,31 +29,31 @@ fn match_tuple(_1: (u32, bool, Option<i32>, u32)) -> u32 {
 
     bb2: {
         _2 = discriminant((_1.2: std::option::Option<i32>)); // scope 0 at $DIR/exponential_or.rs:+2:37: +2:55
-        switchInt(move _2) -> [0_isize: bb4, 1_isize: bb3, otherwise: bb1]; // scope 0 at $DIR/exponential_or.rs:+2:37: +2:55
+        switchInt(move _2) -> [0: bb4, 1: bb3, otherwise: bb1]; // scope 0 at $DIR/exponential_or.rs:+2:37: +2:55
     }
 
     bb3: {
-        switchInt((((_1.2: std::option::Option<i32>) as Some).0: i32)) -> [1_i32: bb4, 8_i32: bb4, otherwise: bb1]; // scope 0 at $DIR/exponential_or.rs:+2:37: +2:55
+        switchInt((((_1.2: std::option::Option<i32>) as Some).0: i32)) -> [1: bb4, 8: bb4, otherwise: bb1]; // scope 0 at $DIR/exponential_or.rs:+2:37: +2:55
     }
 
     bb4: {
         _5 = Le(const 6_u32, (_1.3: u32)); // scope 0 at $DIR/exponential_or.rs:+2:62: +2:67
-        switchInt(move _5) -> [false: bb6, otherwise: bb5]; // scope 0 at $DIR/exponential_or.rs:+2:62: +2:67
+        switchInt(move _5) -> [0: bb6, otherwise: bb5]; // scope 0 at $DIR/exponential_or.rs:+2:62: +2:67
     }
 
     bb5: {
         _6 = Le((_1.3: u32), const 9_u32); // scope 0 at $DIR/exponential_or.rs:+2:62: +2:67
-        switchInt(move _6) -> [false: bb6, otherwise: bb8]; // scope 0 at $DIR/exponential_or.rs:+2:62: +2:67
+        switchInt(move _6) -> [0: bb6, otherwise: bb8]; // scope 0 at $DIR/exponential_or.rs:+2:62: +2:67
     }
 
     bb6: {
         _3 = Le(const 13_u32, (_1.3: u32)); // scope 0 at $DIR/exponential_or.rs:+2:70: +2:77
-        switchInt(move _3) -> [false: bb1, otherwise: bb7]; // scope 0 at $DIR/exponential_or.rs:+2:70: +2:77
+        switchInt(move _3) -> [0: bb1, otherwise: bb7]; // scope 0 at $DIR/exponential_or.rs:+2:70: +2:77
     }
 
     bb7: {
         _4 = Le((_1.3: u32), const 16_u32); // scope 0 at $DIR/exponential_or.rs:+2:70: +2:77
-        switchInt(move _4) -> [false: bb1, otherwise: bb8]; // scope 0 at $DIR/exponential_or.rs:+2:70: +2:77
+        switchInt(move _4) -> [0: bb1, otherwise: bb8]; // scope 0 at $DIR/exponential_or.rs:+2:70: +2:77
     }
 
     bb8: {
index 6ab63e82e35d28fdda6e0c376f47344509a50d56..c1c2cde71ab5b38f485885cd7f3a60bc4f13ad37 100644 (file)
@@ -47,7 +47,7 @@
       bb1: {
           StorageDead(_5);                 // scope 0 at $DIR/funky_arms.rs:+4:36: +4:37
           StorageLive(_6);                 // scope 1 at $DIR/funky_arms.rs:+8:9: +8:13
-          switchInt(_4) -> [false: bb3, otherwise: bb2]; // scope 1 at $DIR/funky_arms.rs:+8:16: +8:32
+          switchInt(_4) -> [0: bb3, otherwise: bb2]; // scope 1 at $DIR/funky_arms.rs:+8:16: +8:32
       }
   
       bb2: {
@@ -75,7 +75,7 @@
       bb5: {
           StorageDead(_8);                 // scope 3 at $DIR/funky_arms.rs:+13:44: +13:45
           _9 = discriminant(_7);           // scope 3 at $DIR/funky_arms.rs:+13:12: +13:27
-          switchInt(move _9) -> [1_isize: bb6, otherwise: bb8]; // scope 3 at $DIR/funky_arms.rs:+13:12: +13:27
+          switchInt(move _9) -> [1: bb6, otherwise: bb8]; // scope 3 at $DIR/funky_arms.rs:+13:12: +13:27
       }
   
       bb6: {
index c3b08bf0648925498c1891d1ecda038e9dfd02db..a8e090020c3d31bb70ee083e59d02adc982a4d36 100644 (file)
@@ -29,7 +29,7 @@ fn main::{closure#0}(_1: *mut [generator@$DIR/generator_drop_cleanup.rs:10:15: 1
 
     bb0: {
         _8 = discriminant((*_1));        // scope 0 at $DIR/generator_drop_cleanup.rs:+0:15: +3:6
-        switchInt(move _8) -> [0_u32: bb7, 3_u32: bb10, otherwise: bb11]; // scope 0 at $DIR/generator_drop_cleanup.rs:+0:15: +3:6
+        switchInt(move _8) -> [0: bb7, 3: bb10, otherwise: bb11]; // scope 0 at $DIR/generator_drop_cleanup.rs:+0:15: +3:6
     }
 
     bb1: {
index fee6da2c6352ff5b7667252d7ea87927938ae1c2..b3d3c768a5dd9a22ded6107eec3ec9f87c196c3c 100644 (file)
@@ -32,7 +32,7 @@ fn main::{closure#0}(_1: Pin<&mut [generator@$DIR/generator_tiny.rs:19:16: 19:24
 
     bb0: {
         _11 = discriminant((*(_1.0: &mut [generator@$DIR/generator_tiny.rs:19:16: 19:24]))); // scope 0 at $DIR/generator_tiny.rs:+0:16: +6:6
-        switchInt(move _11) -> [0_u32: bb1, 3_u32: bb5, otherwise: bb6]; // scope 0 at $DIR/generator_tiny.rs:+0:16: +6:6
+        switchInt(move _11) -> [0: bb1, 3: bb5, otherwise: bb6]; // scope 0 at $DIR/generator_tiny.rs:+0:16: +6:6
     }
 
     bb1: {
index 94180d203439902eabd66afd82477437b955c12d..de4235c9e9e935f7e65cf743d98593365495d122 100644 (file)
@@ -9,7 +9,7 @@
       bb0: {
           StorageLive(_2);                 // scope 0 at $DIR/if_condition_int.rs:+1:8: +1:9
           _2 = _1;                         // scope 0 at $DIR/if_condition_int.rs:+1:8: +1:9
-          switchInt(move _2) -> [false: bb2, otherwise: bb1]; // scope 0 at $DIR/if_condition_int.rs:+1:8: +1:9
+          switchInt(move _2) -> [0: bb2, otherwise: bb1]; // scope 0 at $DIR/if_condition_int.rs:+1:8: +1:9
       }
   
       bb1: {
index b22c7eac622f543108726d383573110ba91e7c0c..754c6579af08fc3c91bc1a645e18e45ebe6090ba 100644 (file)
@@ -13,7 +13,7 @@
           _3 = _1;                         // scope 0 at $DIR/if_condition_int.rs:+1:8: +1:9
           _2 = Eq(move _3, const -42f32);  // scope 0 at $DIR/if_condition_int.rs:+1:8: +1:18
           StorageDead(_3);                 // scope 0 at $DIR/if_condition_int.rs:+1:17: +1:18
-          switchInt(move _2) -> [false: bb2, otherwise: bb1]; // scope 0 at $DIR/if_condition_int.rs:+1:8: +1:18
+          switchInt(move _2) -> [0: bb2, otherwise: bb1]; // scope 0 at $DIR/if_condition_int.rs:+1:8: +1:18
       }
   
       bb1: {
index cc0995f99cfdf237b7a02e21de93c3bf9bc61173..ff23839e29179fa1bb413e5ac09d2ac5820f2800 100644 (file)
           _3 = _1;                         // scope 0 at $DIR/if_condition_int.rs:+1:13: +1:14
 -         _2 = Eq(move _3, const 17_i8);   // scope 0 at $DIR/if_condition_int.rs:+1:13: +1:20
 -         StorageDead(_3);                 // scope 0 at $DIR/if_condition_int.rs:+1:19: +1:20
--         switchInt(_2) -> [false: bb2, otherwise: bb1]; // scope 1 at $DIR/if_condition_int.rs:+2:5: +2:12
+-         switchInt(_2) -> [0: bb2, otherwise: bb1]; // scope 1 at $DIR/if_condition_int.rs:+2:5: +2:12
 +         _2 = Eq(_3, const 17_i8);        // scope 0 at $DIR/if_condition_int.rs:+1:13: +1:20
 +         nop;                             // scope 0 at $DIR/if_condition_int.rs:+1:19: +1:20
-+         switchInt(move _3) -> [17_i8: bb1, otherwise: bb2]; // scope 1 at $DIR/if_condition_int.rs:+2:5: +2:12
++         switchInt(move _3) -> [17: bb1, otherwise: bb2]; // scope 1 at $DIR/if_condition_int.rs:+2:5: +2:12
       }
   
       bb1: {
index 801ea04020343105f203f423acd6466b509fe54e..5964d76a4b96f24149c2bddbf3081d38f05a1cbe 100644 (file)
           _3 = _1;                         // scope 0 at $DIR/if_condition_int.rs:+1:8: +1:9
 -         _2 = Eq(move _3, const 'x');     // scope 0 at $DIR/if_condition_int.rs:+1:8: +1:16
 -         StorageDead(_3);                 // scope 0 at $DIR/if_condition_int.rs:+1:15: +1:16
--         switchInt(move _2) -> [false: bb2, otherwise: bb1]; // scope 0 at $DIR/if_condition_int.rs:+1:8: +1:16
+-         switchInt(move _2) -> [0: bb2, otherwise: bb1]; // scope 0 at $DIR/if_condition_int.rs:+1:8: +1:16
 +         nop;                             // scope 0 at $DIR/if_condition_int.rs:+1:8: +1:16
 +         nop;                             // scope 0 at $DIR/if_condition_int.rs:+1:15: +1:16
-+         switchInt(move _3) -> ['x': bb1, otherwise: bb2]; // scope 0 at $DIR/if_condition_int.rs:+1:8: +1:16
++         switchInt(move _3) -> [120: bb1, otherwise: bb2]; // scope 0 at $DIR/if_condition_int.rs:+1:8: +1:16
       }
   
       bb1: {
index 4297f4d646645e4570a9f98090aea9c15664374e..98918cc743ce0efb6ad9f3661b30b3f4a21c9178 100644 (file)
           _3 = _1;                         // scope 0 at $DIR/if_condition_int.rs:+1:8: +1:9
 -         _2 = Eq(move _3, const 42_i8);   // scope 0 at $DIR/if_condition_int.rs:+1:8: +1:15
 -         StorageDead(_3);                 // scope 0 at $DIR/if_condition_int.rs:+1:14: +1:15
--         switchInt(move _2) -> [false: bb2, otherwise: bb1]; // scope 0 at $DIR/if_condition_int.rs:+1:8: +1:15
+-         switchInt(move _2) -> [0: bb2, otherwise: bb1]; // scope 0 at $DIR/if_condition_int.rs:+1:8: +1:15
 +         nop;                             // scope 0 at $DIR/if_condition_int.rs:+1:8: +1:15
 +         nop;                             // scope 0 at $DIR/if_condition_int.rs:+1:14: +1:15
-+         switchInt(move _3) -> [42_i8: bb1, otherwise: bb2]; // scope 0 at $DIR/if_condition_int.rs:+1:8: +1:15
++         switchInt(move _3) -> [42: bb1, otherwise: bb2]; // scope 0 at $DIR/if_condition_int.rs:+1:8: +1:15
       }
   
       bb1: {
index 8fb794abbd41fa89bba3dc7f76beeb00ea45d580..db38140b8d00b576c2bdbe4626894202908cb8d2 100644 (file)
           _3 = _1;                         // scope 0 at $DIR/if_condition_int.rs:+1:8: +1:9
 -         _2 = Eq(move _3, const 42_u32);  // scope 0 at $DIR/if_condition_int.rs:+1:8: +1:15
 -         StorageDead(_3);                 // scope 0 at $DIR/if_condition_int.rs:+1:14: +1:15
--         switchInt(move _2) -> [false: bb2, otherwise: bb1]; // scope 0 at $DIR/if_condition_int.rs:+1:8: +1:15
+-         switchInt(move _2) -> [0: bb2, otherwise: bb1]; // scope 0 at $DIR/if_condition_int.rs:+1:8: +1:15
 +         nop;                             // scope 0 at $DIR/if_condition_int.rs:+1:8: +1:15
 +         nop;                             // scope 0 at $DIR/if_condition_int.rs:+1:14: +1:15
-+         switchInt(move _3) -> [42_u32: bb1, otherwise: bb2]; // scope 0 at $DIR/if_condition_int.rs:+1:8: +1:15
++         switchInt(move _3) -> [42: bb1, otherwise: bb2]; // scope 0 at $DIR/if_condition_int.rs:+1:8: +1:15
       }
   
       bb1: {
           _5 = _1;                         // scope 0 at $DIR/if_condition_int.rs:+3:15: +3:16
 -         _4 = Ne(move _5, const 21_u32);  // scope 0 at $DIR/if_condition_int.rs:+3:15: +3:22
 -         StorageDead(_5);                 // scope 0 at $DIR/if_condition_int.rs:+3:21: +3:22
--         switchInt(move _4) -> [false: bb4, otherwise: bb3]; // scope 0 at $DIR/if_condition_int.rs:+3:15: +3:22
+-         switchInt(move _4) -> [0: bb4, otherwise: bb3]; // scope 0 at $DIR/if_condition_int.rs:+3:15: +3:22
 +         nop;                             // scope 0 at $DIR/if_condition_int.rs:+3:15: +3:22
 +         nop;                             // scope 0 at $DIR/if_condition_int.rs:+3:21: +3:22
-+         switchInt(move _5) -> [21_u32: bb4, otherwise: bb3]; // scope 0 at $DIR/if_condition_int.rs:+3:15: +3:22
++         switchInt(move _5) -> [21: bb4, otherwise: bb3]; // scope 0 at $DIR/if_condition_int.rs:+3:15: +3:22
       }
   
       bb3: {
index 992253ea780d933cd4e2da77454e495b352c3480..1a1ac4caafaf0ee363dbd4097aab1cf5137604de 100644 (file)
           _3 = _1;                         // scope 0 at $DIR/if_condition_int.rs:+1:8: +1:9
 -         _2 = Eq(move _3, const -42_i32); // scope 0 at $DIR/if_condition_int.rs:+1:8: +1:16
 -         StorageDead(_3);                 // scope 0 at $DIR/if_condition_int.rs:+1:15: +1:16
--         switchInt(move _2) -> [false: bb2, otherwise: bb1]; // scope 0 at $DIR/if_condition_int.rs:+1:8: +1:16
+-         switchInt(move _2) -> [0: bb2, otherwise: bb1]; // scope 0 at $DIR/if_condition_int.rs:+1:8: +1:16
 +         nop;                             // scope 0 at $DIR/if_condition_int.rs:+1:8: +1:16
 +         nop;                             // scope 0 at $DIR/if_condition_int.rs:+1:15: +1:16
-+         switchInt(move _3) -> [-42_i32: bb1, otherwise: bb2]; // scope 0 at $DIR/if_condition_int.rs:+1:8: +1:16
++         switchInt(move _3) -> [4294967254: bb1, otherwise: bb2]; // scope 0 at $DIR/if_condition_int.rs:+1:8: +1:16
       }
   
       bb1: {
index 7cea9472d3a05e4172bb242e65bdb972f6bb9cab..fc3f50227dcb93718c1e48496ecc29160c5d905c 100644 (file)
           _3 = _1;                         // scope 0 at $DIR/if_condition_int.rs:+1:8: +1:9
 -         _2 = Eq(move _3, const 42_u32);  // scope 0 at $DIR/if_condition_int.rs:+1:8: +1:15
 -         StorageDead(_3);                 // scope 0 at $DIR/if_condition_int.rs:+1:14: +1:15
--         switchInt(move _2) -> [false: bb2, otherwise: bb1]; // scope 0 at $DIR/if_condition_int.rs:+1:8: +1:15
+-         switchInt(move _2) -> [0: bb2, otherwise: bb1]; // scope 0 at $DIR/if_condition_int.rs:+1:8: +1:15
 +         nop;                             // scope 0 at $DIR/if_condition_int.rs:+1:8: +1:15
 +         nop;                             // scope 0 at $DIR/if_condition_int.rs:+1:14: +1:15
-+         switchInt(move _3) -> [42_u32: bb1, otherwise: bb2]; // scope 0 at $DIR/if_condition_int.rs:+1:8: +1:15
++         switchInt(move _3) -> [42: bb1, otherwise: bb2]; // scope 0 at $DIR/if_condition_int.rs:+1:8: +1:15
       }
   
       bb1: {
index 5f3ee467c88cb026144d63eff156b74d19306742..afe157ccd7faa3d08361122791c41967f3014620 100644 (file)
@@ -10,8 +10,6 @@
 +         let _3: ();                      // in scope 1 at $DIR/cycle.rs:6:5: 6:8
 +         let mut _4: &fn() {main};        // in scope 1 at $DIR/cycle.rs:6:5: 6:6
 +         let mut _5: ();                  // in scope 1 at $DIR/cycle.rs:6:5: 6:8
-+         scope 2 (inlined <fn() {main} as Fn<()>>::call - shim(fn() {main})) { // at $DIR/cycle.rs:6:5: 6:8
-+         }
 +     }
   
       bb0: {
 +         StorageLive(_4);                 // scope 1 at $DIR/cycle.rs:6:5: 6:6
 +         _4 = &_2;                        // scope 1 at $DIR/cycle.rs:6:5: 6:6
 +         StorageLive(_5);                 // scope 1 at $DIR/cycle.rs:6:5: 6:8
-+         _3 = move (*_4)() -> [return: bb4, unwind: bb2]; // scope 2 at $SRC_DIR/core/src/ops/function.rs:LL:COL
++         _3 = <fn() {main} as Fn<()>>::call(move _4, move _5) -> [return: bb2, unwind: bb3]; // scope 1 at $DIR/cycle.rs:6:5: 6:8
++                                          // mir::Constant
++                                          // + span: $DIR/cycle.rs:6:5: 6:6
++                                          // + literal: Const { ty: for<'a> extern "rust-call" fn(&'a fn() {main}, ()) -> <fn() {main} as FnOnce<()>>::Output {<fn() {main} as Fn<()>>::call}, val: Value(<ZST>) }
       }
   
       bb1: {
           return;                          // scope 0 at $DIR/cycle.rs:+2:2: +2:2
 +     }
 + 
-+     bb2 (cleanup): {
-+         drop(_2) -> bb3;                 // scope 1 at $DIR/cycle.rs:7:1: 7:2
++     bb2: {
++         StorageDead(_5);                 // scope 1 at $DIR/cycle.rs:6:7: 6:8
++         StorageDead(_4);                 // scope 1 at $DIR/cycle.rs:6:7: 6:8
++         StorageDead(_3);                 // scope 1 at $DIR/cycle.rs:6:8: 6:9
++         drop(_2) -> bb1;                 // scope 1 at $DIR/cycle.rs:7:1: 7:2
 +     }
 + 
 +     bb3 (cleanup): {
-+         resume;                          // scope 1 at $DIR/cycle.rs:5:1: 7:2
++         drop(_2) -> bb4;                 // scope 1 at $DIR/cycle.rs:7:1: 7:2
 +     }
 + 
-+     bb4: {
-+         StorageDead(_5);                 // scope 1 at $DIR/cycle.rs:6:7: 6:8
-+         StorageDead(_4);                 // scope 1 at $DIR/cycle.rs:6:7: 6:8
-+         StorageDead(_3);                 // scope 1 at $DIR/cycle.rs:6:8: 6:9
-+         drop(_2) -> bb1;                 // scope 1 at $DIR/cycle.rs:7:1: 7:2
++     bb4 (cleanup): {
++         resume;                          // scope 1 at $DIR/cycle.rs:5:1: 7:2
       }
   }
   
index 8b4099b9d9f71b10dfe6d17630dc5d2b861f418f..bd89e09ecd148b4e52384621802be95f24c94e43 100644 (file)
 +         let _3: ();                      // in scope 1 at $DIR/cycle.rs:6:5: 6:8
 +         let mut _4: &fn() {g};           // in scope 1 at $DIR/cycle.rs:6:5: 6:6
 +         let mut _5: ();                  // in scope 1 at $DIR/cycle.rs:6:5: 6:8
-+         scope 2 (inlined <fn() {g} as Fn<()>>::call - shim(fn() {g})) { // at $DIR/cycle.rs:6:5: 6:8
-+             scope 3 (inlined g) {        // at $SRC_DIR/core/src/ops/function.rs:LL:COL
-+                 let mut _6: fn() {main}; // in scope 3 at $DIR/cycle.rs:12:5: 12:12
-+                 scope 4 (inlined f::<fn() {main}>) { // at $DIR/cycle.rs:12:5: 12:12
-+                     debug g => _6;       // in scope 4 at $DIR/cycle.rs:5:6: 5:7
-+                     let _7: ();          // in scope 4 at $DIR/cycle.rs:6:5: 6:8
-+                     let mut _8: &fn() {main}; // in scope 4 at $DIR/cycle.rs:6:5: 6:6
-+                     scope 5 (inlined <fn() {main} as Fn<()>>::call - shim(fn() {main})) { // at $DIR/cycle.rs:6:5: 6:8
-+                     }
-+                 }
-+             }
-+         }
 +     }
   
       bb0: {
 +         StorageLive(_4);                 // scope 1 at $DIR/cycle.rs:6:5: 6:6
 +         _4 = &_2;                        // scope 1 at $DIR/cycle.rs:6:5: 6:6
 +         StorageLive(_5);                 // scope 1 at $DIR/cycle.rs:6:5: 6:8
-+         StorageLive(_6);                 // scope 3 at $DIR/cycle.rs:12:5: 12:12
-+         StorageLive(_7);                 // scope 4 at $DIR/cycle.rs:6:5: 6:8
-+         StorageLive(_8);                 // scope 4 at $DIR/cycle.rs:6:5: 6:6
-+         _8 = &_6;                        // scope 4 at $DIR/cycle.rs:6:5: 6:6
-+         _7 = move (*_8)() -> [return: bb4, unwind: bb2]; // scope 5 at $SRC_DIR/core/src/ops/function.rs:LL:COL
++         _3 = <fn() {g} as Fn<()>>::call(move _4, move _5) -> [return: bb2, unwind: bb3]; // scope 1 at $DIR/cycle.rs:6:5: 6:8
++                                          // mir::Constant
++                                          // + span: $DIR/cycle.rs:6:5: 6:6
++                                          // + literal: Const { ty: for<'a> extern "rust-call" fn(&'a fn() {g}, ()) -> <fn() {g} as FnOnce<()>>::Output {<fn() {g} as Fn<()>>::call}, val: Value(<ZST>) }
       }
   
       bb1: {
           return;                          // scope 0 at $DIR/cycle.rs:+2:2: +2:2
 +     }
 + 
-+     bb2 (cleanup): {
-+         drop(_2) -> bb3;                 // scope 1 at $DIR/cycle.rs:7:1: 7:2
++     bb2: {
++         StorageDead(_5);                 // scope 1 at $DIR/cycle.rs:6:7: 6:8
++         StorageDead(_4);                 // scope 1 at $DIR/cycle.rs:6:7: 6:8
++         StorageDead(_3);                 // scope 1 at $DIR/cycle.rs:6:8: 6:9
++         drop(_2) -> bb1;                 // scope 1 at $DIR/cycle.rs:7:1: 7:2
 +     }
 + 
 +     bb3 (cleanup): {
-+         resume;                          // scope 1 at $DIR/cycle.rs:5:1: 7:2
++         drop(_2) -> bb4;                 // scope 1 at $DIR/cycle.rs:7:1: 7:2
 +     }
 + 
-+     bb4: {
-+         StorageDead(_8);                 // scope 4 at $DIR/cycle.rs:6:7: 6:8
-+         StorageDead(_7);                 // scope 4 at $DIR/cycle.rs:6:8: 6:9
-+         StorageDead(_6);                 // scope 3 at $DIR/cycle.rs:12:5: 12:12
-+         StorageDead(_5);                 // scope 1 at $DIR/cycle.rs:6:7: 6:8
-+         StorageDead(_4);                 // scope 1 at $DIR/cycle.rs:6:7: 6:8
-+         StorageDead(_3);                 // scope 1 at $DIR/cycle.rs:6:8: 6:9
-+         drop(_2) -> bb1;                 // scope 1 at $DIR/cycle.rs:7:1: 7:2
++     bb4 (cleanup): {
++         resume;                          // scope 1 at $DIR/cycle.rs:5:1: 7:2
       }
   }
   
diff --git a/src/test/mir-opt/inline/exponential_runtime.main.Inline.diff b/src/test/mir-opt/inline/exponential_runtime.main.Inline.diff
new file mode 100644 (file)
index 0000000..d9fd7b3
--- /dev/null
@@ -0,0 +1,50 @@
+- // MIR for `main` before Inline
++ // MIR for `main` after Inline
+  
+  fn main() -> () {
+      let mut _0: ();                      // return place in scope 0 at $DIR/exponential_runtime.rs:+0:11: +0:11
+      let _1: ();                          // in scope 0 at $DIR/exponential_runtime.rs:+1:5: +1:22
++     scope 1 (inlined <() as G>::call) {  // at $DIR/exponential_runtime.rs:86:5: 86:22
++         let _2: ();                      // in scope 1 at $DIR/exponential_runtime.rs:73:9: 73:25
++         let _3: ();                      // in scope 1 at $DIR/exponential_runtime.rs:74:9: 74:25
++         let _4: ();                      // in scope 1 at $DIR/exponential_runtime.rs:75:9: 75:25
++     }
+  
+      bb0: {
+          StorageLive(_1);                 // scope 0 at $DIR/exponential_runtime.rs:+1:5: +1:22
+-         _1 = <() as G>::call() -> bb1;   // scope 0 at $DIR/exponential_runtime.rs:+1:5: +1:22
++         StorageLive(_2);                 // scope 1 at $DIR/exponential_runtime.rs:73:9: 73:25
++         _2 = <() as F>::call() -> bb1;   // scope 1 at $DIR/exponential_runtime.rs:73:9: 73:25
+                                           // mir::Constant
+-                                          // + span: $DIR/exponential_runtime.rs:86:5: 86:20
+-                                          // + literal: Const { ty: fn() {<() as G>::call}, val: Value(<ZST>) }
++                                          // + span: $DIR/exponential_runtime.rs:73:9: 73:23
++                                          // + literal: Const { ty: fn() {<() as F>::call}, val: Value(<ZST>) }
+      }
+  
+      bb1: {
++         StorageDead(_2);                 // scope 1 at $DIR/exponential_runtime.rs:73:25: 73:26
++         StorageLive(_3);                 // scope 1 at $DIR/exponential_runtime.rs:74:9: 74:25
++         _3 = <() as F>::call() -> bb2;   // scope 1 at $DIR/exponential_runtime.rs:74:9: 74:25
++                                          // mir::Constant
++                                          // + span: $DIR/exponential_runtime.rs:74:9: 74:23
++                                          // + literal: Const { ty: fn() {<() as F>::call}, val: Value(<ZST>) }
++     }
++ 
++     bb2: {
++         StorageDead(_3);                 // scope 1 at $DIR/exponential_runtime.rs:74:25: 74:26
++         StorageLive(_4);                 // scope 1 at $DIR/exponential_runtime.rs:75:9: 75:25
++         _4 = <() as F>::call() -> bb3;   // scope 1 at $DIR/exponential_runtime.rs:75:9: 75:25
++                                          // mir::Constant
++                                          // + span: $DIR/exponential_runtime.rs:75:9: 75:23
++                                          // + literal: Const { ty: fn() {<() as F>::call}, val: Value(<ZST>) }
++     }
++ 
++     bb3: {
++         StorageDead(_4);                 // scope 1 at $DIR/exponential_runtime.rs:75:25: 75:26
+          StorageDead(_1);                 // scope 0 at $DIR/exponential_runtime.rs:+1:22: +1:23
+          _0 = const ();                   // scope 0 at $DIR/exponential_runtime.rs:+0:11: +2:2
+          return;                          // scope 0 at $DIR/exponential_runtime.rs:+2:2: +2:2
+      }
+  }
+  
diff --git a/src/test/mir-opt/inline/exponential_runtime.rs b/src/test/mir-opt/inline/exponential_runtime.rs
new file mode 100644 (file)
index 0000000..d9219d7
--- /dev/null
@@ -0,0 +1,87 @@
+// Checks that code with exponential runtime does not have exponential behavior in inlining.
+
+trait A {
+    fn call();
+}
+
+trait B {
+    fn call();
+}
+impl<T: A> B for T {
+    #[inline]
+    fn call() {
+        <T as A>::call();
+        <T as A>::call();
+        <T as A>::call();
+    }
+}
+
+trait C {
+    fn call();
+}
+impl<T: B> C for T {
+    #[inline]
+    fn call() {
+        <T as B>::call();
+        <T as B>::call();
+        <T as B>::call();
+    }
+}
+
+trait D {
+    fn call();
+}
+impl<T: C> D for T {
+    #[inline]
+    fn call() {
+        <T as C>::call();
+        <T as C>::call();
+        <T as C>::call();
+    }
+}
+
+trait E {
+    fn call();
+}
+impl<T: D> E for T {
+    #[inline]
+    fn call() {
+        <T as D>::call();
+        <T as D>::call();
+        <T as D>::call();
+    }
+}
+
+trait F {
+    fn call();
+}
+impl<T: E> F for T {
+    #[inline]
+    fn call() {
+        <T as E>::call();
+        <T as E>::call();
+        <T as E>::call();
+    }
+}
+
+trait G {
+    fn call();
+}
+impl<T: F> G for T {
+    #[inline]
+    fn call() {
+        <T as F>::call();
+        <T as F>::call();
+        <T as F>::call();
+    }
+}
+
+impl A for () {
+    #[inline(never)]
+    fn call() {}
+}
+
+// EMIT_MIR exponential_runtime.main.Inline.diff
+fn main() {
+    <() as G>::call();
+}
index 5510cd7bc8ced1d003fbd3b3fd914263c1466c44..f54a1a747d47436aba941cb1ab4df23f43bad2b4 100644 (file)
@@ -5,20 +5,17 @@
       let mut _0: ();                      // return place in scope 0 at $DIR/inline_cycle.rs:+0:10: +0:10
       let _1: ();                          // in scope 0 at $DIR/inline_cycle.rs:+1:5: +1:24
 +     scope 1 (inlined <C as Call>::call) { // at $DIR/inline_cycle.rs:14:5: 14:24
-+         scope 2 (inlined <A<C> as Call>::call) { // at $DIR/inline_cycle.rs:43:9: 43:23
-+             scope 3 (inlined <B<C> as Call>::call) { // at $DIR/inline_cycle.rs:28:9: 28:31
-+             }
-+         }
 +     }
   
       bb0: {
           StorageLive(_1);                 // scope 0 at $DIR/inline_cycle.rs:+1:5: +1:24
 -         _1 = <C as Call>::call() -> bb1; // scope 0 at $DIR/inline_cycle.rs:+1:5: +1:24
-+         _1 = <C as Call>::call() -> bb1; // scope 3 at $DIR/inline_cycle.rs:36:9: 36:28
++         _1 = <A<C> as Call>::call() -> bb1; // scope 1 at $DIR/inline_cycle.rs:43:9: 43:23
                                            // mir::Constant
 -                                          // + span: $DIR/inline_cycle.rs:14:5: 14:22
-+                                          // + span: $DIR/inline_cycle.rs:36:9: 36:26
-                                           // + literal: Const { ty: fn() {<C as Call>::call}, val: Value(<ZST>) }
+-                                          // + literal: Const { ty: fn() {<C as Call>::call}, val: Value(<ZST>) }
++                                          // + span: $DIR/inline_cycle.rs:43:9: 43:21
++                                          // + literal: Const { ty: fn() {<A<C> as Call>::call}, val: Value(<ZST>) }
       }
   
       bb1: {
index ab1ea0e3b2c24d91b667c8ddbc06c96de2e088e0..a940848c269cda8d5a5a98dd968f334f687dd0a4 100644 (file)
@@ -9,11 +9,6 @@
 +         debug f => _2;                   // in scope 1 at $DIR/inline_cycle.rs:53:22: 53:23
 +         let _3: ();                      // in scope 1 at $DIR/inline_cycle.rs:54:5: 54:8
 +         let mut _4: ();                  // in scope 1 at $DIR/inline_cycle.rs:54:5: 54:8
-+         scope 2 (inlined <fn() {f} as FnOnce<()>>::call_once - shim(fn() {f})) { // at $DIR/inline_cycle.rs:54:5: 54:8
-+             scope 3 (inlined f) {        // at $SRC_DIR/core/src/ops/function.rs:LL:COL
-+                 let _5: ();              // in scope 3 at $DIR/inline_cycle.rs:59:5: 59:12
-+             }
-+         }
 +     }
   
       bb0: {
 +         _2 = f;                          // scope 0 at $DIR/inline_cycle.rs:+1:5: +1:12
                                            // mir::Constant
 -                                          // + span: $DIR/inline_cycle.rs:49:5: 49:9
-+                                          // + span: $DIR/inline_cycle.rs:49:10: 49:11
-+                                          // + literal: Const { ty: fn() {f}, val: Value(<ZST>) }
+-                                          // + literal: Const { ty: fn(fn() {f}) {call::<fn() {f}>}, val: Value(<ZST>) }
+-                                          // mir::Constant
+                                           // + span: $DIR/inline_cycle.rs:49:10: 49:11
+                                           // + literal: Const { ty: fn() {f}, val: Value(<ZST>) }
 +         StorageLive(_3);                 // scope 1 at $DIR/inline_cycle.rs:54:5: 54:8
 +         StorageLive(_4);                 // scope 1 at $DIR/inline_cycle.rs:54:5: 54:8
-+         StorageLive(_5);                 // scope 3 at $DIR/inline_cycle.rs:59:5: 59:12
-+         _5 = call::<fn() {f}>(f) -> bb1; // scope 3 at $DIR/inline_cycle.rs:59:5: 59:12
++         _3 = <fn() {f} as FnOnce<()>>::call_once(move _2, move _4) -> bb1; // scope 1 at $DIR/inline_cycle.rs:54:5: 54:8
 +                                          // mir::Constant
-+                                          // + span: $DIR/inline_cycle.rs:59:5: 59:9
-                                           // + literal: Const { ty: fn(fn() {f}) {call::<fn() {f}>}, val: Value(<ZST>) }
-                                           // mir::Constant
--                                          // + span: $DIR/inline_cycle.rs:49:10: 49:11
-+                                          // + span: $DIR/inline_cycle.rs:59:10: 59:11
-                                           // + literal: Const { ty: fn() {f}, val: Value(<ZST>) }
++                                          // + span: $DIR/inline_cycle.rs:54:5: 54:6
++                                          // + literal: Const { ty: extern "rust-call" fn(fn() {f}, ()) -> <fn() {f} as FnOnce<()>>::Output {<fn() {f} as FnOnce<()>>::call_once}, val: Value(<ZST>) }
       }
   
       bb1: {
-+         StorageDead(_5);                 // scope 3 at $DIR/inline_cycle.rs:59:12: 59:13
 +         StorageDead(_4);                 // scope 1 at $DIR/inline_cycle.rs:54:7: 54:8
 +         StorageDead(_3);                 // scope 1 at $DIR/inline_cycle.rs:54:8: 54:9
 +         StorageDead(_2);                 // scope 0 at $DIR/inline_cycle.rs:+1:5: +1:12
index 52debab4dd1c0348ed20ea66294415146254c6f6..04de3e61e5ff81f6b148d18fae783ac62bad7dc8 100644 (file)
@@ -6,21 +6,18 @@
       let _1: ();                          // in scope 0 at $DIR/inline_cycle_generic.rs:+1:5: +1:24
 +     scope 1 (inlined <C as Call>::call) { // at $DIR/inline_cycle_generic.rs:9:5: 9:24
 +         scope 2 (inlined <B<A> as Call>::call) { // at $DIR/inline_cycle_generic.rs:38:9: 38:31
-+             scope 3 (inlined <A as Call>::call) { // at $DIR/inline_cycle_generic.rs:31:9: 31:28
-+                 scope 4 (inlined <B<C> as Call>::call) { // at $DIR/inline_cycle_generic.rs:23:9: 23:31
-+                 }
-+             }
 +         }
 +     }
   
       bb0: {
           StorageLive(_1);                 // scope 0 at $DIR/inline_cycle_generic.rs:+1:5: +1:24
 -         _1 = <C as Call>::call() -> bb1; // scope 0 at $DIR/inline_cycle_generic.rs:+1:5: +1:24
-+         _1 = <C as Call>::call() -> bb1; // scope 4 at $DIR/inline_cycle_generic.rs:31:9: 31:28
++         _1 = <A as Call>::call() -> bb1; // scope 2 at $DIR/inline_cycle_generic.rs:31:9: 31:28
                                            // mir::Constant
 -                                          // + span: $DIR/inline_cycle_generic.rs:9:5: 9:22
+-                                          // + literal: Const { ty: fn() {<C as Call>::call}, val: Value(<ZST>) }
 +                                          // + span: $DIR/inline_cycle_generic.rs:31:9: 31:26
-                                           // + literal: Const { ty: fn() {<C as Call>::call}, val: Value(<ZST>) }
++                                          // + literal: Const { ty: fn() {<A as Call>::call}, val: Value(<ZST>) }
       }
   
       bb1: {
index 1e703a8fd2baf357508020763b0776f6e2c45245..b787a19f4b21c0d9c82050872e791553984abcbc 100644 (file)
@@ -19,7 +19,7 @@
           _3 = _1;                         // scope 0 at $DIR/inline_diverging.rs:+1:8: +1:9
           _2 = Gt(move _3, const 0_i32);   // scope 0 at $DIR/inline_diverging.rs:+1:8: +1:13
           StorageDead(_3);                 // scope 0 at $DIR/inline_diverging.rs:+1:12: +1:13
-          switchInt(move _2) -> [false: bb2, otherwise: bb1]; // scope 0 at $DIR/inline_diverging.rs:+1:8: +1:13
+          switchInt(move _2) -> [0: bb2, otherwise: bb1]; // scope 0 at $DIR/inline_diverging.rs:+1:8: +1:13
       }
   
       bb1: {
index 75a6ab3700898e2a05ab3cbf1e3c1e0829af9058..a01bcf1645b0571fe7f662353b5bf6ce1db23725 100644 (file)
 +             scope 3 {
 +                 debug b => _9;           // in scope 3 at $DIR/inline_diverging.rs:28:9: 28:10
 +             }
-+             scope 6 (inlined <fn() -> ! {sleep} as Fn<()>>::call - shim(fn() -> ! {sleep})) { // at $DIR/inline_diverging.rs:28:13: 28:16
-+                 scope 7 (inlined sleep) { // at $SRC_DIR/core/src/ops/function.rs:LL:COL
-+                 }
-+             }
-+         }
-+         scope 4 (inlined <fn() -> ! {sleep} as Fn<()>>::call - shim(fn() -> ! {sleep})) { // at $DIR/inline_diverging.rs:27:13: 27:16
-+             scope 5 (inlined sleep) {    // at $SRC_DIR/core/src/ops/function.rs:LL:COL
-+             }
 +         }
 +     }
   
 +         StorageLive(_4);                 // scope 1 at $DIR/inline_diverging.rs:27:13: 27:14
 +         _4 = &_2;                        // scope 1 at $DIR/inline_diverging.rs:27:13: 27:14
 +         StorageLive(_5);                 // scope 1 at $DIR/inline_diverging.rs:27:13: 27:16
-+         goto -> bb1;                     // scope 5 at $DIR/inline_diverging.rs:39:5: 39:12
++         _3 = <fn() -> ! {sleep} as Fn<()>>::call(move _4, move _5) -> [return: bb1, unwind: bb5]; // scope 1 at $DIR/inline_diverging.rs:27:13: 27:16
++                                          // mir::Constant
++                                          // + span: $DIR/inline_diverging.rs:27:13: 27:14
++                                          // + literal: Const { ty: for<'a> extern "rust-call" fn(&'a fn() -> ! {sleep}, ()) -> <fn() -> ! {sleep} as FnOnce<()>>::Output {<fn() -> ! {sleep} as Fn<()>>::call}, val: Value(<ZST>) }
 +     }
 + 
 +     bb1: {
-+         goto -> bb1;                     // scope 5 at $DIR/inline_diverging.rs:39:5: 39:12
++         StorageDead(_5);                 // scope 1 at $DIR/inline_diverging.rs:27:15: 27:16
++         StorageDead(_4);                 // scope 1 at $DIR/inline_diverging.rs:27:15: 27:16
++         StorageLive(_6);                 // scope 2 at $DIR/inline_diverging.rs:28:13: 28:14
++         _6 = &_2;                        // scope 2 at $DIR/inline_diverging.rs:28:13: 28:14
++         StorageLive(_7);                 // scope 2 at $DIR/inline_diverging.rs:28:13: 28:16
++         _9 = <fn() -> ! {sleep} as Fn<()>>::call(move _6, move _7) -> [return: bb2, unwind: bb4]; // scope 2 at $DIR/inline_diverging.rs:28:13: 28:16
++                                          // mir::Constant
++                                          // + span: $DIR/inline_diverging.rs:28:13: 28:14
++                                          // + literal: Const { ty: for<'a> extern "rust-call" fn(&'a fn() -> ! {sleep}, ()) -> <fn() -> ! {sleep} as FnOnce<()>>::Output {<fn() -> ! {sleep} as Fn<()>>::call}, val: Value(<ZST>) }
++     }
++ 
++     bb2: {
++         StorageDead(_7);                 // scope 2 at $DIR/inline_diverging.rs:28:15: 28:16
++         StorageDead(_6);                 // scope 2 at $DIR/inline_diverging.rs:28:15: 28:16
++         StorageLive(_8);                 // scope 3 at $DIR/inline_diverging.rs:29:6: 29:7
++         _8 = move _3;                    // scope 3 at $DIR/inline_diverging.rs:29:6: 29:7
++         Deinit(_1);                      // scope 3 at $DIR/inline_diverging.rs:29:5: 29:11
++         (_1.0: !) = move _8;             // scope 3 at $DIR/inline_diverging.rs:29:5: 29:11
++         (_1.1: !) = move _9;             // scope 3 at $DIR/inline_diverging.rs:29:5: 29:11
++         StorageDead(_8);                 // scope 3 at $DIR/inline_diverging.rs:29:10: 29:11
++         StorageDead(_3);                 // scope 1 at $DIR/inline_diverging.rs:30:1: 30:2
++         drop(_2) -> bb3;                 // scope 1 at $DIR/inline_diverging.rs:30:1: 30:2
++     }
++ 
++     bb3: {
++         unreachable;                     // scope 0 at $DIR/inline_diverging.rs:30:2: 30:2
++     }
++ 
++     bb4 (cleanup): {
++         drop(_3) -> bb5;                 // scope 1 at $DIR/inline_diverging.rs:30:1: 30:2
++     }
++ 
++     bb5 (cleanup): {
++         drop(_2) -> bb6;                 // scope 1 at $DIR/inline_diverging.rs:30:1: 30:2
++     }
++ 
++     bb6 (cleanup): {
++         resume;                          // scope 1 at $DIR/inline_diverging.rs:26:1: 30:2
       }
   }
   
index 91bff3d3234db25ab9dbcccf089da7d0e3492e54..bd21405f14b3fcc663cbefef4caa0fb860c690d1 100644 (file)
@@ -72,7 +72,7 @@
 +         _7 = const false;                // scope 0 at $DIR/inline_generator.rs:+1:14: +1:46
 +         _10 = deref_copy (_2.0: &mut [generator@$DIR/inline_generator.rs:15:5: 15:8]); // scope 6 at $DIR/inline_generator.rs:15:5: 15:41
 +         _9 = discriminant((*_10));       // scope 6 at $DIR/inline_generator.rs:15:5: 15:41
-+         switchInt(move _9) -> [0_u32: bb3, 1_u32: bb8, 3_u32: bb7, otherwise: bb9]; // scope 6 at $DIR/inline_generator.rs:15:5: 15:41
++         switchInt(move _9) -> [0: bb3, 1: bb8, 3: bb7, otherwise: bb9]; // scope 6 at $DIR/inline_generator.rs:15:5: 15:41
       }
   
 -     bb3: {
@@ -92,7 +92,7 @@
 + 
 +     bb3: {
 +         StorageLive(_8);                 // scope 6 at $DIR/inline_generator.rs:15:17: 15:39
-+         switchInt(move _7) -> [false: bb5, otherwise: bb4]; // scope 6 at $DIR/inline_generator.rs:15:20: 15:21
++         switchInt(move _7) -> [0: bb5, otherwise: bb4]; // scope 6 at $DIR/inline_generator.rs:15:20: 15:21
 +     }
 + 
 +     bb4: {
index 75af20d482ddd22d88088d9cde6f977031e5a541..60149ff36064ecc3d87e433209e01328f5dc1843 100644 (file)
@@ -38,9 +38,7 @@ fn bar() -> bool {
                                          // + literal: Const { ty: &i32, val: Unevaluated(bar, [], Some(promoted[1])) }
         Retag(_10);                      // scope 1 at $DIR/inline_retag.rs:+2:7: +2:9
         _4 = &(*_10);                    // scope 1 at $DIR/inline_retag.rs:+2:7: +2:9
-        Retag(_4);                       // scope 1 at $DIR/inline_retag.rs:+2:7: +2:9
         _3 = &(*_4);                     // scope 1 at $DIR/inline_retag.rs:+2:7: +2:9
-        Retag(_3);                       // scope 1 at $DIR/inline_retag.rs:+2:7: +2:9
         StorageLive(_6);                 // scope 1 at $DIR/inline_retag.rs:+2:11: +2:14
         StorageLive(_7);                 // scope 1 at $DIR/inline_retag.rs:+2:11: +2:14
         _9 = const _;                    // scope 1 at $DIR/inline_retag.rs:+2:11: +2:14
@@ -49,9 +47,7 @@ fn bar() -> bool {
                                          // + literal: Const { ty: &i32, val: Unevaluated(bar, [], Some(promoted[0])) }
         Retag(_9);                       // scope 1 at $DIR/inline_retag.rs:+2:11: +2:14
         _7 = &(*_9);                     // scope 1 at $DIR/inline_retag.rs:+2:11: +2:14
-        Retag(_7);                       // scope 1 at $DIR/inline_retag.rs:+2:11: +2:14
         _6 = &(*_7);                     // scope 1 at $DIR/inline_retag.rs:+2:11: +2:14
-        Retag(_6);                       // scope 1 at $DIR/inline_retag.rs:+2:11: +2:14
         Retag(_3);                       // scope 2 at $DIR/inline_retag.rs:16:8: 16:9
         Retag(_6);                       // scope 2 at $DIR/inline_retag.rs:16:17: 16:18
         StorageLive(_11);                // scope 2 at $DIR/inline_retag.rs:17:5: 17:7
index 7a54beca2336c06a16b08a36c7466415056b0174..36ddb189e0d3365eabea7fa2a977a89d9cb29fdf 100644 (file)
@@ -39,7 +39,7 @@
 +         StorageLive(_6);                 // scope 2 at $DIR/inline_shims.rs:+2:14: +2:40
 +         StorageLive(_7);                 // scope 2 at $DIR/inline_shims.rs:+2:14: +2:40
 +         _6 = discriminant((*_5));        // scope 3 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL
-+         switchInt(move _6) -> [0_isize: bb2, otherwise: bb3]; // scope 3 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL
++         switchInt(move _6) -> [0: bb2, otherwise: bb3]; // scope 3 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL
       }
   
       bb2: {
index 81d5528231db65fb0437724d99cde06f9dd27b0c..2f6f5f87efcc7a8c911a53a449660f9f0b61c53f 100644 (file)
@@ -26,7 +26,7 @@
       }
   
       bb3: {
-          switchInt(move _2) -> [false: bb5, otherwise: bb4]; // scope 0 at /the/src/instrument_coverage.rs:+2:12: +2:17
+          switchInt(move _2) -> [0: bb5, otherwise: bb4]; // scope 0 at /the/src/instrument_coverage.rs:+2:12: +2:17
       }
   
       bb4: {
index 82210081832c88d9a8d153963876aa7b1092e677..b0d5b291b6cb55c734a24f0f43c19eed94c4b341 100644 (file)
@@ -26,7 +26,7 @@ fn main() -> () {
         StorageLive(_3);                 // scope 1 at $DIR/issue_38669.rs:+3:9: +5:10
         StorageLive(_4);                 // scope 1 at $DIR/issue_38669.rs:+3:12: +3:24
         _4 = _1;                         // scope 1 at $DIR/issue_38669.rs:+3:12: +3:24
-        switchInt(move _4) -> [false: bb4, otherwise: bb3]; // scope 1 at $DIR/issue_38669.rs:+3:12: +3:24
+        switchInt(move _4) -> [0: bb4, otherwise: bb3]; // scope 1 at $DIR/issue_38669.rs:+3:12: +3:24
     }
 
     bb3: {
index c573ad5a8e4a406e385813b39ec2b70042761e60..c2ea3ac502f89dc3f89446f4700bea44444d19a4 100644 (file)
@@ -65,6 +65,6 @@ fn main() -> () {
     }
 
     bb8 (cleanup): {
-        switchInt(_5) -> [false: bb6, otherwise: bb7]; // scope 0 at $DIR/issue_41110.rs:+1:27: +1:28
+        switchInt(_5) -> [0: bb6, otherwise: bb7]; // scope 0 at $DIR/issue_41110.rs:+1:27: +1:28
     }
 }
index 470b032328184926af5acdefc16d5ebed1932bca..82989c3f071b43d39f022ca6dadc2e802aa7404e 100644 (file)
@@ -96,6 +96,6 @@ fn test() -> () {
     }
 
     bb14 (cleanup): {
-        switchInt(_6) -> [false: bb10, otherwise: bb13]; // scope 0 at $DIR/issue_41110.rs:+5:1: +5:2
+        switchInt(_6) -> [0: bb10, otherwise: bb13]; // scope 0 at $DIR/issue_41110.rs:+5:1: +5:2
     }
 }
index 73372c97bea7287fc19ed0388a8856ab1428ca81..00504273245b1d2a9acb320e5a5929061fb6a401 100644 (file)
@@ -33,7 +33,7 @@ fn main() -> () {
     }
 
     bb1: {
-        switchInt(move _2) -> [false: bb7, otherwise: bb2]; // scope 1 at $DIR/issue_41888.rs:+2:8: +2:14
+        switchInt(move _2) -> [0: bb7, otherwise: bb2]; // scope 1 at $DIR/issue_41888.rs:+2:8: +2:14
     }
 
     bb2: {
@@ -52,7 +52,7 @@ fn main() -> () {
     bb4: {
         StorageDead(_3);                 // scope 1 at $DIR/issue_41888.rs:+3:19: +3:20
         _5 = discriminant(_1);           // scope 2 at $DIR/issue_41888.rs:+4:16: +4:24
-        switchInt(move _5) -> [0_isize: bb5, otherwise: bb6]; // scope 2 at $DIR/issue_41888.rs:+4:16: +4:24
+        switchInt(move _5) -> [0: bb5, otherwise: bb6]; // scope 2 at $DIR/issue_41888.rs:+4:16: +4:24
     }
 
     bb5: {
@@ -134,19 +134,19 @@ fn main() -> () {
 
     bb19: {
         _10 = discriminant(_1);          // scope 0 at $DIR/issue_41888.rs:+9:1: +9:2
-        switchInt(move _10) -> [0_isize: bb15, otherwise: bb17]; // scope 0 at $DIR/issue_41888.rs:+9:1: +9:2
+        switchInt(move _10) -> [0: bb15, otherwise: bb17]; // scope 0 at $DIR/issue_41888.rs:+9:1: +9:2
     }
 
     bb20: {
-        switchInt(_7) -> [false: bb15, otherwise: bb19]; // scope 0 at $DIR/issue_41888.rs:+9:1: +9:2
+        switchInt(_7) -> [0: bb15, otherwise: bb19]; // scope 0 at $DIR/issue_41888.rs:+9:1: +9:2
     }
 
     bb21 (cleanup): {
         _11 = discriminant(_1);          // scope 0 at $DIR/issue_41888.rs:+9:1: +9:2
-        switchInt(move _11) -> [0_isize: bb16, otherwise: bb18]; // scope 0 at $DIR/issue_41888.rs:+9:1: +9:2
+        switchInt(move _11) -> [0: bb16, otherwise: bb18]; // scope 0 at $DIR/issue_41888.rs:+9:1: +9:2
     }
 
     bb22 (cleanup): {
-        switchInt(_7) -> [false: bb12, otherwise: bb21]; // scope 0 at $DIR/issue_41888.rs:+9:1: +9:2
+        switchInt(_7) -> [0: bb12, otherwise: bb21]; // scope 0 at $DIR/issue_41888.rs:+9:1: +9:2
     }
 }
index 6969a66ac19253a321282731d812fc2bb11c11f1..adfa3a7733b1d6ed1819c1b7a829d2939c7fade5 100644 (file)
@@ -52,7 +52,7 @@ fn test() -> Option<Box<u32>> {
     bb2: {
         StorageDead(_7);                 // scope 0 at $DIR/issue_62289.rs:+1:19: +1:20
         _8 = discriminant(_6);           // scope 0 at $DIR/issue_62289.rs:+1:15: +1:20
-        switchInt(move _8) -> [0_isize: bb3, 1_isize: bb5, otherwise: bb4]; // scope 0 at $DIR/issue_62289.rs:+1:15: +1:20
+        switchInt(move _8) -> [0: bb3, 1: bb5, otherwise: bb4]; // scope 0 at $DIR/issue_62289.rs:+1:15: +1:20
     }
 
     bb3: {
index b88cdfcbc96c257f403fef974795d5d0aeaaf627..17b81633991fec12dfa7ead2aa8edb71d8080e89 100644 (file)
           StorageDead(_17);                // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
           _15 = Not(move _16);             // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
           StorageDead(_16);                // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          switchInt(move _15) -> [false: bb5, otherwise: bb4]; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          switchInt(move _15) -> [0: bb5, otherwise: bb4]; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
       }
   
       bb4: {
index 3db40412b2ef47dc727e11d56429671df7c361ee..3e035c18db862f3adcda96875dce95195dda1ca9 100644 (file)
@@ -109,7 +109,7 @@ fn main() -> () {
         StorageDead(_12);                // scope 1 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
         _10 = Not(move _11);             // scope 1 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
         StorageDead(_11);                // scope 1 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-        switchInt(move _10) -> [false: bb4, otherwise: bb3]; // scope 1 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+        switchInt(move _10) -> [0: bb4, otherwise: bb3]; // scope 1 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
     }
 
     bb3: {
@@ -218,7 +218,7 @@ fn main() -> () {
         StorageDead(_33);                // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
         _31 = Not(move _32);             // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
         StorageDead(_32);                // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-        switchInt(move _31) -> [false: bb13, otherwise: bb12]; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+        switchInt(move _31) -> [0: bb13, otherwise: bb12]; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
     }
 
     bb12: {
index 5a2f4feff355263fa2db23b1d4e01977aee90145..e0d6b58f229c4a63be620ad3d46b16ac70629b9e 100644 (file)
@@ -47,7 +47,7 @@ fn num_to_digit(_1: char) -> u32 {
 
     bb2: {
         _7 = discriminant(_2);           // scope 3 at $SRC_DIR/core/src/option.rs:LL:COL
-        switchInt(move _7) -> [0_isize: bb6, 1_isize: bb8, otherwise: bb7]; // scope 3 at $SRC_DIR/core/src/option.rs:LL:COL
+        switchInt(move _7) -> [0: bb6, 1: bb8, otherwise: bb7]; // scope 3 at $SRC_DIR/core/src/option.rs:LL:COL
     }
 
     bb3: {
@@ -66,7 +66,7 @@ fn num_to_digit(_1: char) -> u32 {
         StorageDead(_4);                 // scope 1 at $SRC_DIR/core/src/char/methods.rs:LL:COL
         StorageDead(_5);                 // scope 1 at $SRC_DIR/core/src/char/methods.rs:LL:COL
         StorageDead(_3);                 // scope 0 at $DIR/issue_59352.rs:+2:8: +2:23
-        switchInt(move _9) -> [1_isize: bb1, otherwise: bb3]; // scope 0 at $DIR/issue_59352.rs:+2:8: +2:23
+        switchInt(move _9) -> [1: bb1, otherwise: bb3]; // scope 0 at $DIR/issue_59352.rs:+2:8: +2:23
     }
 
     bb6: {
index 87066cc62c02a6b1e32dbab67c84bd7931997890..1c69a6232d60631e30f8b36dc538819916abf6bc 100644 (file)
   
       bb1: {
           StorageDead(_3);                 // scope 2 at $DIR/issue_75439.rs:+2:52: +2:53
-          switchInt(_2[0 of 4]) -> [0_u32: bb2, otherwise: bb8]; // scope 3 at $DIR/issue_75439.rs:+4:12: +4:30
+          switchInt(_2[0 of 4]) -> [0: bb2, otherwise: bb8]; // scope 3 at $DIR/issue_75439.rs:+4:12: +4:30
       }
   
       bb2: {
-          switchInt(_2[1 of 4]) -> [0_u32: bb3, otherwise: bb8]; // scope 3 at $DIR/issue_75439.rs:+4:12: +4:30
+          switchInt(_2[1 of 4]) -> [0: bb3, otherwise: bb8]; // scope 3 at $DIR/issue_75439.rs:+4:12: +4:30
       }
   
       bb3: {
-          switchInt(_2[2 of 4]) -> [0_u32: bb5, 4294901760_u32: bb6, otherwise: bb8]; // scope 3 at $DIR/issue_75439.rs:+4:12: +4:30
+          switchInt(_2[2 of 4]) -> [0: bb5, 4294901760: bb6, otherwise: bb8]; // scope 3 at $DIR/issue_75439.rs:+4:12: +4:30
       }
   
       bb4: {
index 5981ab885f90c9beea07295c5c0ef9e38a95a110..4ee2dae49b3f34652228d4b6b1379a4249313edf 100644 (file)
@@ -16,7 +16,7 @@ fn main() -> () {
         StorageLive(_1);                 // scope 0 at $DIR/loop_test.rs:+4:5: +6:6
         StorageLive(_2);                 // scope 0 at $DIR/loop_test.rs:+4:8: +4:12
         _2 = const true;                 // scope 0 at $DIR/loop_test.rs:+4:8: +4:12
-        switchInt(move _2) -> [false: bb2, otherwise: bb1]; // scope 0 at $DIR/loop_test.rs:+4:8: +4:12
+        switchInt(move _2) -> [0: bb2, otherwise: bb1]; // scope 0 at $DIR/loop_test.rs:+4:8: +4:12
     }
 
     bb1: {
index 049bbeac867f90a036751cca8a500e072a8e45d9..9bc7060e958ebf56c4083692fc647fcc9d746149 100644 (file)
@@ -38,7 +38,7 @@
           _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: bb4, otherwise: bb2]; // scope 0 at $DIR/lower_array_len.rs:+1:8: +1:27
+          switchInt(move _3) -> [0: bb4, otherwise: bb2]; // scope 0 at $DIR/lower_array_len.rs:+1:8: +1:27
       }
   
       bb2: {
index 40ec01eeb41a61167fce7775f2ac7287e1fa08b9..cf427cfd1e6dbb7a71c4b57401847c4b37cc500a 100644 (file)
@@ -41,7 +41,7 @@
           _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: bb4, otherwise: bb2]; // scope 0 at $DIR/lower_array_len.rs:+1:8: +1:27
+          switchInt(move _3) -> [0: bb4, otherwise: bb2]; // scope 0 at $DIR/lower_array_len.rs:+1:8: +1:27
       }
   
       bb2: {
index 9b1b07f38fcd3307627ad291a64371f8331df376..701c2ad705af2997fdf4e501f706819260a5bd27 100644 (file)
@@ -19,7 +19,7 @@ fn array_bound(_1: usize, _2: &[u8; N]) -> u8 {
         _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
+        switchInt(move _3) -> [0: bb3, otherwise: bb1]; // scope 0 at $DIR/lower_array_len_e2e.rs:+1:8: +1:27
     }
 
     bb1: {
index 29e379777b05894b824527199ce3f90e331c1938..0440cfce2893f152437667e746632f89763ecb4b 100644 (file)
@@ -22,7 +22,7 @@ fn array_bound_mut(_1: usize, _2: &mut [u8; N]) -> u8 {
         _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
+        switchInt(move _3) -> [0: bb3, otherwise: bb1]; // scope 0 at $DIR/lower_array_len_e2e.rs:+1:8: +1:27
     }
 
     bb1: {
index 5f5d6e68fdc17eeb606bde560efdaedee37e3f87..2b0370cf35800c3f157f81008023abdd6348d4c6 100644 (file)
@@ -33,7 +33,7 @@
           _3 = Lt(move _4, move _5);       // scope 0 at $DIR/lower_slice_len.rs:+1:8: +1:27
           StorageDead(_5);                 // scope 0 at $DIR/lower_slice_len.rs:+1:26: +1:27
           StorageDead(_4);                 // scope 0 at $DIR/lower_slice_len.rs:+1:26: +1:27
-          switchInt(move _3) -> [false: bb4, otherwise: bb2]; // scope 0 at $DIR/lower_slice_len.rs:+1:8: +1:27
+          switchInt(move _3) -> [0: bb4, otherwise: bb2]; // scope 0 at $DIR/lower_slice_len.rs:+1:8: +1:27
       }
   
       bb2: {
index d3db3b182717d3c2a1177b421aef1cb92ce4a218..84e4d35f908170560e24550e7d6239ecd7cdeae1 100644 (file)
   
       bb0: {
 -         FakeRead(ForMatchedPlace(None), _2); // scope 0 at $DIR/match_arm_scopes.rs:+1:11: +1:16
--         switchInt((_2.0: bool)) -> [false: bb1, otherwise: bb2]; // scope 0 at $DIR/match_arm_scopes.rs:+1:5: +1:16
-+         switchInt((_2.0: bool)) -> [false: bb5, otherwise: bb1]; // scope 0 at $DIR/match_arm_scopes.rs:+1:5: +1:16
+-         switchInt((_2.0: bool)) -> [0: bb1, otherwise: bb2]; // scope 0 at $DIR/match_arm_scopes.rs:+1:5: +1:16
++         switchInt((_2.0: bool)) -> [0: bb5, otherwise: bb1]; // scope 0 at $DIR/match_arm_scopes.rs:+1:5: +1:16
       }
   
       bb1: {
 -         falseEdge -> [real: bb8, imaginary: bb3]; // scope 0 at $DIR/match_arm_scopes.rs:+2:9: +2:22
-+         switchInt((_2.1: bool)) -> [false: bb10, otherwise: bb2]; // scope 0 at $DIR/match_arm_scopes.rs:+1:5: +1:16
++         switchInt((_2.1: bool)) -> [0: bb10, otherwise: bb2]; // scope 0 at $DIR/match_arm_scopes.rs:+1:5: +1:16
       }
   
       bb2: {
--         switchInt((_2.1: bool)) -> [false: bb3, otherwise: bb4]; // scope 0 at $DIR/match_arm_scopes.rs:+1:5: +1:16
-+         switchInt((_2.0: bool)) -> [false: bb3, otherwise: bb17]; // scope 0 at $DIR/match_arm_scopes.rs:+1:5: +1:16
+-         switchInt((_2.1: bool)) -> [0: bb3, otherwise: bb4]; // scope 0 at $DIR/match_arm_scopes.rs:+1:5: +1:16
++         switchInt((_2.0: bool)) -> [0: bb3, otherwise: bb17]; // scope 0 at $DIR/match_arm_scopes.rs:+1:5: +1:16
       }
   
       bb3: {
@@ -51,7 +51,7 @@
 -     }
 - 
 -     bb4: {
--         switchInt((_2.0: bool)) -> [false: bb6, otherwise: bb5]; // scope 0 at $DIR/match_arm_scopes.rs:+1:5: +1:16
+-         switchInt((_2.0: bool)) -> [0: bb6, otherwise: bb5]; // scope 0 at $DIR/match_arm_scopes.rs:+1:5: +1:16
 -     }
 - 
 -     bb5: {
@@ -85,8 +85,8 @@
           StorageLive(_9);                 // scope 0 at $DIR/match_arm_scopes.rs:+2:42: +2:73
           StorageLive(_10);                // scope 0 at $DIR/match_arm_scopes.rs:+2:45: +2:49
           _10 = _1;                        // scope 0 at $DIR/match_arm_scopes.rs:+2:45: +2:49
--         switchInt(move _10) -> [false: bb10, otherwise: bb9]; // scope 0 at $DIR/match_arm_scopes.rs:+2:45: +2:49
-+         switchInt(move _10) -> [false: bb7, otherwise: bb6]; // scope 0 at $DIR/match_arm_scopes.rs:+2:45: +2:49
+-         switchInt(move _10) -> [0: bb10, otherwise: bb9]; // scope 0 at $DIR/match_arm_scopes.rs:+2:45: +2:49
++         switchInt(move _10) -> [0: bb7, otherwise: bb6]; // scope 0 at $DIR/match_arm_scopes.rs:+2:45: +2:49
       }
   
 -     bb9: {
 -     bb10: {
 +     bb7: {
           _9 = (*_6);                      // scope 0 at $DIR/match_arm_scopes.rs:+2:70: +2:71
--         switchInt(move _9) -> [false: bb12, otherwise: bb11]; // scope 0 at $DIR/match_arm_scopes.rs:+2:42: +2:73
-+         switchInt(move _9) -> [false: bb9, otherwise: bb8]; // scope 0 at $DIR/match_arm_scopes.rs:+2:42: +2:73
+-         switchInt(move _9) -> [0: bb12, otherwise: bb11]; // scope 0 at $DIR/match_arm_scopes.rs:+2:42: +2:73
++         switchInt(move _9) -> [0: bb9, otherwise: bb8]; // scope 0 at $DIR/match_arm_scopes.rs:+2:42: +2:73
       }
   
 -     bb11: {
           StorageLive(_12);                // scope 0 at $DIR/match_arm_scopes.rs:+2:42: +2:73
           StorageLive(_13);                // scope 0 at $DIR/match_arm_scopes.rs:+2:45: +2:49
           _13 = _1;                        // scope 0 at $DIR/match_arm_scopes.rs:+2:45: +2:49
--         switchInt(move _13) -> [false: bb15, otherwise: bb14]; // scope 0 at $DIR/match_arm_scopes.rs:+2:45: +2:49
-+         switchInt(move _13) -> [false: bb12, otherwise: bb11]; // scope 0 at $DIR/match_arm_scopes.rs:+2:45: +2:49
+-         switchInt(move _13) -> [0: bb15, otherwise: bb14]; // scope 0 at $DIR/match_arm_scopes.rs:+2:45: +2:49
++         switchInt(move _13) -> [0: bb12, otherwise: bb11]; // scope 0 at $DIR/match_arm_scopes.rs:+2:45: +2:49
       }
   
 -     bb14: {
 -     bb15: {
 +     bb12: {
           _12 = (*_6);                     // scope 0 at $DIR/match_arm_scopes.rs:+2:70: +2:71
--         switchInt(move _12) -> [false: bb17, otherwise: bb16]; // scope 0 at $DIR/match_arm_scopes.rs:+2:42: +2:73
-+         switchInt(move _12) -> [false: bb14, otherwise: bb13]; // scope 0 at $DIR/match_arm_scopes.rs:+2:42: +2:73
+-         switchInt(move _12) -> [0: bb17, otherwise: bb16]; // scope 0 at $DIR/match_arm_scopes.rs:+2:42: +2:73
++         switchInt(move _12) -> [0: bb14, otherwise: bb13]; // scope 0 at $DIR/match_arm_scopes.rs:+2:42: +2:73
       }
   
 -     bb16: {
index b184ffc404e6bb05d6eadcde84a7b86deda955f8..d51dbf4258c541ba8eb8bde8b49c1fdd325f335c 100644 (file)
@@ -28,12 +28,12 @@ fn main() -> () {
         StorageLive(_3);                 // scope 2 at $DIR/match_test.rs:+6:5: +11:6
         FakeRead(ForMatchedPlace(None), _1); // scope 2 at $DIR/match_test.rs:+6:11: +6:12
         _6 = Le(const 0_i32, _1);        // scope 2 at $DIR/match_test.rs:+7:9: +7:14
-        switchInt(move _6) -> [false: bb4, otherwise: bb1]; // scope 2 at $DIR/match_test.rs:+7:9: +7:14
+        switchInt(move _6) -> [0: bb4, otherwise: bb1]; // scope 2 at $DIR/match_test.rs:+7:9: +7:14
     }
 
     bb1: {
         _7 = Lt(_1, const 10_i32);       // scope 2 at $DIR/match_test.rs:+7:9: +7:14
-        switchInt(move _7) -> [false: bb4, otherwise: bb2]; // scope 2 at $DIR/match_test.rs:+7:9: +7:14
+        switchInt(move _7) -> [0: bb4, otherwise: bb2]; // scope 2 at $DIR/match_test.rs:+7:9: +7:14
     }
 
     bb2: {
@@ -47,12 +47,12 @@ fn main() -> () {
 
     bb4: {
         _4 = Le(const 10_i32, _1);       // scope 2 at $DIR/match_test.rs:+8:9: +8:16
-        switchInt(move _4) -> [false: bb7, otherwise: bb5]; // scope 2 at $DIR/match_test.rs:+8:9: +8:16
+        switchInt(move _4) -> [0: bb7, otherwise: bb5]; // scope 2 at $DIR/match_test.rs:+8:9: +8:16
     }
 
     bb5: {
         _5 = Le(_1, const 20_i32);       // scope 2 at $DIR/match_test.rs:+8:9: +8:16
-        switchInt(move _5) -> [false: bb7, otherwise: bb6]; // scope 2 at $DIR/match_test.rs:+8:9: +8:16
+        switchInt(move _5) -> [0: bb7, otherwise: bb6]; // scope 2 at $DIR/match_test.rs:+8:9: +8:16
     }
 
     bb6: {
@@ -60,7 +60,7 @@ fn main() -> () {
     }
 
     bb7: {
-        switchInt(_1) -> [-1_i32: bb8, otherwise: bb3]; // scope 2 at $DIR/match_test.rs:+6:5: +6:12
+        switchInt(_1) -> [4294967295: bb8, otherwise: bb3]; // scope 2 at $DIR/match_test.rs:+6:5: +6:12
     }
 
     bb8: {
@@ -71,7 +71,7 @@ fn main() -> () {
         _8 = &shallow _1;                // scope 2 at $DIR/match_test.rs:+6:11: +6:12
         StorageLive(_9);                 // scope 2 at $DIR/match_test.rs:+7:18: +7:19
         _9 = _2;                         // scope 2 at $DIR/match_test.rs:+7:18: +7:19
-        switchInt(move _9) -> [false: bb11, otherwise: bb10]; // scope 2 at $DIR/match_test.rs:+7:18: +7:19
+        switchInt(move _9) -> [0: bb11, otherwise: bb10]; // scope 2 at $DIR/match_test.rs:+7:18: +7:19
     }
 
     bb10: {
index f9eeb1ea5b96095be840b3afd1c193409cdb55ba..be91b0bfe6820f1ea61ef4ee00ab1d9ca4109a06 100644 (file)
@@ -33,7 +33,7 @@
           StorageLive(_4);                 // scope 2 at $DIR/matches_reduce_branches.rs:+3:9: +3:10
           StorageLive(_5);                 // scope 3 at $DIR/matches_reduce_branches.rs:+4:9: +4:10
           StorageLive(_6);                 // scope 4 at $DIR/matches_reduce_branches.rs:+6:5: +21:6
--         switchInt(_1) -> [7_i32: bb2, otherwise: bb1]; // scope 4 at $DIR/matches_reduce_branches.rs:+6:5: +6:12
+-         switchInt(_1) -> [7: bb2, otherwise: bb1]; // scope 4 at $DIR/matches_reduce_branches.rs:+6:5: +6:12
 -     }
 - 
 -     bb1: {
index 0b40b3be8bdd41efd5e773ab32228a05b64f394c..aa8092ece663a7e53b8cd3efa017ffc6cf763c8e 100644 (file)
       bb0: {
           StorageLive(_2);                 // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
           _3 = discriminant(_1);           // scope 0 at $DIR/matches_reduce_branches.rs:+1:17: +1:20
--         switchInt(move _3) -> [0_isize: bb2, otherwise: bb1]; // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+-         switchInt(move _3) -> [0: 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
++         switchInt(move _2) -> [0: bb2, otherwise: bb1]; // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
       }
   
       bb1: {
@@ -30,7 +30,7 @@
 -     }
 - 
 -     bb3: {
--         switchInt(move _2) -> [false: bb5, otherwise: bb4]; // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+-         switchInt(move _2) -> [0: bb5, otherwise: bb4]; // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
 -     }
 - 
 -     bb4: {
index b8c7722cd3713c905b31331b98b0cc2623594660..193104dd30e7e3e711c46390732435ce5cfd704e 100644 (file)
@@ -26,7 +26,7 @@
           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
+-         switchInt(move _6) -> [0: bb2, otherwise: bb1]; // scope 0 at $DIR/matches_reduce_branches.rs:+2:24: +2:28
 -     }
 - 
 -     bb1: {
@@ -45,7 +45,7 @@
 +         _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
+-         switchInt(move _5) -> [0: bb5, otherwise: bb4]; // scope 0 at $DIR/matches_reduce_branches.rs:+2:21: +2:52
 -     }
 - 
 -     bb4: {
@@ -64,7 +64,7 @@
 +         _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
+-         switchInt(move _4) -> [0: bb8, otherwise: bb7]; // scope 0 at $DIR/matches_reduce_branches.rs:+2:18: +2:76
 -     }
 - 
 -     bb7: {
@@ -78,7 +78,7 @@
 -     }
 - 
 -     bb9: {
--         switchInt(move _3) -> [false: bb11, otherwise: bb10]; // scope 0 at $DIR/matches_reduce_branches.rs:+2:15: +6:10
+-         switchInt(move _3) -> [0: bb11, otherwise: bb10]; // scope 0 at $DIR/matches_reduce_branches.rs:+2:15: +6:10
 -     }
 - 
 -     bb10: {
index 1b4dddc1d43a030a725a4793feb833d5ae40cad4..3766d99a43b3b01d2f8f27702da114456e8a324e 100644 (file)
@@ -8,7 +8,7 @@
   
       bb0: {
           _2 = discriminant(_1);           // scope 0 at $DIR/matches_u8.rs:+1:11: +1:12
-          switchInt(move _2) -> [0_isize: bb3, 1_isize: bb1, otherwise: bb2]; // scope 0 at $DIR/matches_u8.rs:+1:5: +1:12
+          switchInt(move _2) -> [0: bb3, 1: bb1, otherwise: bb2]; // scope 0 at $DIR/matches_u8.rs:+1:5: +1:12
       }
   
       bb1: {
index 6e734852e1af490fec52362d823beb6ab07e7b2d..b5146cd539f396425714f2d50d210e96e6a8e4b1 100644 (file)
@@ -8,7 +8,7 @@
   
       bb0: {
           _2 = discriminant(_1);           // scope 0 at $DIR/matches_u8.rs:+1:11: +1:12
-          switchInt(move _2) -> [0_isize: bb3, 1_isize: bb1, otherwise: bb2]; // scope 0 at $DIR/matches_u8.rs:+1:5: +1:12
+          switchInt(move _2) -> [0: bb3, 1: bb1, otherwise: bb2]; // scope 0 at $DIR/matches_u8.rs:+1:5: +1:12
       }
   
       bb1: {
index 3e3fda6141aec93fb430e9e8dd3853b9baab523c..8e6564a38b0bbbaafe2dfd25125cdb4c2efefaf2 100644 (file)
@@ -62,7 +62,7 @@ fn main() -> () {
         FakeRead(ForLet(None), _6);      // bb1[4]: scope 2 at $DIR/region_subtyping_basic.rs:+3:9: +3:10
         StorageLive(_7);                 // bb1[5]: scope 3 at $DIR/region_subtyping_basic.rs:+4:8: +4:12
         _7 = const ConstValue(Scalar(0x01): bool); // bb1[6]: scope 3 at $DIR/region_subtyping_basic.rs:+4:8: +4:12
-        switchInt(move _7) -> [ConstValue(Scalar(0x00): bool): bb4, otherwise: bb2]; // bb1[7]: scope 3 at $DIR/region_subtyping_basic.rs:+4:8: +4:12
+        switchInt(move _7) -> [0: bb4, otherwise: bb2]; // bb1[7]: scope 3 at $DIR/region_subtyping_basic.rs:+4:8: +4:12
     }
 
     bb2: {
index 39a53702a4cbb6921c0cb35bc5d2e7d6558349ff..74d44c6741a92747b01cf35d5f7d1b52324ff91e 100644 (file)
@@ -62,7 +62,7 @@ fn main() -> () {
         FakeRead(ForLet(None), _6);      // bb1[4]: scope 2 at $DIR/region_subtyping_basic.rs:+3:9: +3:10
         StorageLive(_7);                 // bb1[5]: scope 3 at $DIR/region_subtyping_basic.rs:+4:8: +4:12
         _7 = const ConstValue(Scalar(0x01): bool); // bb1[6]: scope 3 at $DIR/region_subtyping_basic.rs:+4:8: +4:12
-        switchInt(move _7) -> [ConstValue(Scalar(0x00): bool): bb4, otherwise: bb2]; // bb1[7]: scope 3 at $DIR/region_subtyping_basic.rs:+4:8: +4:12
+        switchInt(move _7) -> [0: bb4, otherwise: bb2]; // bb1[7]: scope 3 at $DIR/region_subtyping_basic.rs:+4:8: +4:12
     }
 
     bb2: {
index e708255cea4304adb10b16ef597f21b54dad1b97..69327b7afac7ec3d59cce6f5f5eb20af5501da9a 100644 (file)
@@ -15,7 +15,7 @@ fn unwrap(_1: Option<T>) -> T {
 
     bb0: {
         _2 = discriminant(_1);           // scope 0 at $DIR/no_drop_for_inactive_variant.rs:+1:11: +1:14
-        switchInt(move _2) -> [0_isize: bb1, 1_isize: bb3, otherwise: bb2]; // scope 0 at $DIR/no_drop_for_inactive_variant.rs:+1:5: +1:14
+        switchInt(move _2) -> [0: bb1, 1: bb3, otherwise: bb2]; // scope 0 at $DIR/no_drop_for_inactive_variant.rs:+1:5: +1:14
     }
 
     bb1: {
index 5009d090668f0630c78791906544ea3dbfed39ee..b558c35ac1eeb8a6331e65622ab69bc4364e4cc3 100644 (file)
@@ -14,7 +14,7 @@
 -         _2 = Ne(move _3, const false);   // scope 0 at $DIR/not_equal_false.rs:+1:8: +1:18
 +         _2 = move _3;                    // scope 0 at $DIR/not_equal_false.rs:+1:8: +1:18
           StorageDead(_3);                 // scope 0 at $DIR/not_equal_false.rs:+1:17: +1:18
-          switchInt(move _2) -> [false: bb2, otherwise: bb1]; // scope 0 at $DIR/not_equal_false.rs:+1:8: +1:18
+          switchInt(move _2) -> [0: bb2, otherwise: bb1]; // scope 0 at $DIR/not_equal_false.rs:+1:8: +1:18
       }
   
       bb1: {
index 243a54b6a8454d68ca0a50e4a570535b80be20d9..bb5920b28ca9456e0aae3e953ae2baa5de7d13b5 100644 (file)
@@ -16,7 +16,7 @@
 -         FakeRead(ForMatchedPlace(None), _1); // scope 0 at $DIR/remove_fake_borrows.rs:+1:11: +1:12
 +         nop;                             // scope 0 at $DIR/remove_fake_borrows.rs:+1:11: +1:12
           _3 = discriminant(_1);           // scope 0 at $DIR/remove_fake_borrows.rs:+1:11: +1:12
-          switchInt(move _3) -> [1_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/remove_fake_borrows.rs:+1:5: +1:12
+          switchInt(move _3) -> [1: bb2, otherwise: bb1]; // scope 0 at $DIR/remove_fake_borrows.rs:+1:5: +1:12
       }
   
       bb1: {
@@ -25,7 +25,7 @@
       }
   
       bb2: {
-          switchInt((*(*((_1 as Some).0: &&i32)))) -> [0_i32: bb3, otherwise: bb1]; // scope 0 at $DIR/remove_fake_borrows.rs:+1:5: +1:12
+          switchInt((*(*((_1 as Some).0: &&i32)))) -> [0: bb3, otherwise: bb1]; // scope 0 at $DIR/remove_fake_borrows.rs:+1:5: +1:12
       }
   
       bb3: {
@@ -43,7 +43,7 @@
 +         nop;                             // scope 0 at $DIR/remove_fake_borrows.rs:+1:11: +1:12
           StorageLive(_8);                 // scope 0 at $DIR/remove_fake_borrows.rs:+2:20: +2:21
           _8 = _2;                         // scope 0 at $DIR/remove_fake_borrows.rs:+2:20: +2:21
-          switchInt(move _8) -> [false: bb6, otherwise: bb5]; // scope 0 at $DIR/remove_fake_borrows.rs:+2:20: +2:21
+          switchInt(move _8) -> [0: bb6, otherwise: bb5]; // scope 0 at $DIR/remove_fake_borrows.rs:+2:20: +2:21
       }
   
       bb5: {
index 188aa55649069a7951e43495e09cd43a6fc9d358..ed1d0b87f603373ada39bd462539ebbf2207f29a 100644 (file)
@@ -63,7 +63,7 @@
       bb3: {
 -         StorageDead(_8);                 // scope 2 at $DIR/remove_storage_markers.rs:+2:18: +2:19
           _10 = discriminant(_7);          // scope 2 at $DIR/remove_storage_markers.rs:+2:14: +2:19
-          switchInt(move _10) -> [0_isize: bb6, 1_isize: bb4, otherwise: bb5]; // scope 2 at $DIR/remove_storage_markers.rs:+2:14: +2:19
+          switchInt(move _10) -> [0: bb6, 1: bb4, otherwise: bb5]; // scope 2 at $DIR/remove_storage_markers.rs:+2:14: +2:19
       }
   
       bb4: {
diff --git a/src/test/mir-opt/remove_zsts.get_union.PreCodegen.after.mir b/src/test/mir-opt/remove_zsts.get_union.PreCodegen.after.mir
new file mode 100644 (file)
index 0000000..12e914e
--- /dev/null
@@ -0,0 +1,10 @@
+// MIR for `get_union` after PreCodegen
+
+fn get_union() -> Foo {
+    let mut _0: Foo;                     // return place in scope 0 at $DIR/remove_zsts.rs:+0:19: +0:22
+
+    bb0: {
+        Deinit(_0);                      // scope 0 at $DIR/remove_zsts.rs:+1:5: +1:18
+        return;                          // scope 0 at $DIR/remove_zsts.rs:+2:2: +2:2
+    }
+}
diff --git a/src/test/mir-opt/remove_zsts.get_union.RemoveZsts.diff b/src/test/mir-opt/remove_zsts.get_union.RemoveZsts.diff
new file mode 100644 (file)
index 0000000..169b7b1
--- /dev/null
@@ -0,0 +1,19 @@
+- // MIR for `get_union` before RemoveZsts
++ // MIR for `get_union` after RemoveZsts
+  
+  fn get_union() -> Foo {
+      let mut _0: Foo;                     // return place in scope 0 at $DIR/remove_zsts.rs:+0:19: +0:22
+      let mut _1: ();                      // in scope 0 at $DIR/remove_zsts.rs:+1:14: +1:16
+  
+      bb0: {
+          StorageLive(_1);                 // scope 0 at $DIR/remove_zsts.rs:+1:14: +1:16
+-         Deinit(_1);                      // scope 0 at $DIR/remove_zsts.rs:+1:14: +1:16
++         nop;                             // scope 0 at $DIR/remove_zsts.rs:+1:14: +1:16
+          Deinit(_0);                      // scope 0 at $DIR/remove_zsts.rs:+1:5: +1:18
+-         (_0.0: ()) = move _1;            // scope 0 at $DIR/remove_zsts.rs:+1:5: +1:18
++         nop;                             // scope 0 at $DIR/remove_zsts.rs:+1:5: +1:18
+          StorageDead(_1);                 // scope 0 at $DIR/remove_zsts.rs:+1:17: +1:18
+          return;                          // scope 0 at $DIR/remove_zsts.rs:+2:2: +2:2
+      }
+  }
+  
diff --git a/src/test/mir-opt/remove_zsts.rs b/src/test/mir-opt/remove_zsts.rs
new file mode 100644 (file)
index 0000000..1cf7ad6
--- /dev/null
@@ -0,0 +1,14 @@
+union Foo {
+    x: (),
+    y: u64,
+}
+
+// EMIT_MIR remove_zsts.get_union.RemoveZsts.diff
+// EMIT_MIR remove_zsts.get_union.PreCodegen.after.mir
+fn get_union() -> Foo {
+    Foo { x: () }
+}
+
+fn main() {
+    get_union();
+}
diff --git a/src/test/mir-opt/remove_zsts_dont_touch_unions.get_union.RemoveZsts.after.mir b/src/test/mir-opt/remove_zsts_dont_touch_unions.get_union.RemoveZsts.after.mir
deleted file mode 100644 (file)
index 7d9e604..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-// MIR for `get_union` after RemoveZsts
-
-fn get_union() -> Foo {
-    let mut _0: Foo;                     // return place in scope 0 at $DIR/remove_zsts_dont_touch_unions.rs:+0:19: +0:22
-    let mut _1: ();                      // in scope 0 at $DIR/remove_zsts_dont_touch_unions.rs:+1:14: +1:16
-
-    bb0: {
-        StorageLive(_1);                 // scope 0 at $DIR/remove_zsts_dont_touch_unions.rs:+1:14: +1:16
-        nop;                             // scope 0 at $DIR/remove_zsts_dont_touch_unions.rs:+1:14: +1:16
-        Deinit(_0);                      // scope 0 at $DIR/remove_zsts_dont_touch_unions.rs:+1:5: +1:18
-        (_0.0: ()) = move _1;            // scope 0 at $DIR/remove_zsts_dont_touch_unions.rs:+1:5: +1:18
-        StorageDead(_1);                 // scope 0 at $DIR/remove_zsts_dont_touch_unions.rs:+1:17: +1:18
-        return;                          // scope 0 at $DIR/remove_zsts_dont_touch_unions.rs:+2:2: +2:2
-    }
-}
diff --git a/src/test/mir-opt/remove_zsts_dont_touch_unions.rs b/src/test/mir-opt/remove_zsts_dont_touch_unions.rs
deleted file mode 100644 (file)
index 8b9de9b..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-// unit-test: RemoveZsts
-
-// Ensure RemoveZsts doesn't remove ZST assignments to union fields,
-// which causes problems in Miri.
-
-union Foo {
-    x: (),
-    y: u64,
-}
-
-// EMIT_MIR remove_zsts_dont_touch_unions.get_union.RemoveZsts.after.mir
-fn get_union() -> Foo {
-    Foo { x: () }
-}
-
-
-fn main() {
-    get_union();
-}
index fe57e32a7acc236cc8e7728e8d878db194cd766f..19b726e74845392e72cec5427d02ef1543fd047d 100644 (file)
@@ -68,9 +68,7 @@ fn array_casts() -> () {
         StorageLive(_3);                 // scope 1 at $DIR/retag.rs:+2:13: +2:19
         StorageLive(_4);                 // scope 1 at $DIR/retag.rs:+2:13: +2:19
         _4 = &mut _1;                    // scope 1 at $DIR/retag.rs:+2:13: +2:19
-        Retag(_4);                       // scope 1 at $DIR/retag.rs:+2:13: +2:19
         _3 = &raw mut (*_4);             // scope 1 at $DIR/retag.rs:+2:13: +2:19
-        Retag([raw] _3);                 // scope 1 at $DIR/retag.rs:+2:13: +2:19
         _2 = move _3 as *mut usize (Pointer(ArrayToPointer)); // scope 1 at $DIR/retag.rs:+2:13: +2:33
         StorageDead(_3);                 // scope 1 at $DIR/retag.rs:+2:32: +2:33
         StorageDead(_4);                 // scope 1 at $DIR/retag.rs:+2:33: +2:34
@@ -96,9 +94,7 @@ fn array_casts() -> () {
         StorageLive(_10);                // scope 4 at $DIR/retag.rs:+6:13: +6:15
         StorageLive(_11);                // scope 4 at $DIR/retag.rs:+6:13: +6:15
         _11 = &_8;                       // scope 4 at $DIR/retag.rs:+6:13: +6:15
-        Retag(_11);                      // scope 4 at $DIR/retag.rs:+6:13: +6:15
         _10 = &raw const (*_11);         // scope 4 at $DIR/retag.rs:+6:13: +6:15
-        Retag([raw] _10);                // scope 4 at $DIR/retag.rs:+6:13: +6:15
         _9 = move _10 as *const usize (Pointer(ArrayToPointer)); // scope 4 at $DIR/retag.rs:+6:13: +6:31
         StorageDead(_10);                // scope 4 at $DIR/retag.rs:+6:30: +6:31
         StorageDead(_11);                // scope 4 at $DIR/retag.rs:+6:31: +6:32
@@ -119,7 +115,6 @@ fn array_casts() -> () {
         StorageDead(_17);                // scope 6 at $DIR/retag.rs:+7:33: +7:34
         _15 = (*_16);                    // scope 6 at $DIR/retag.rs:+7:25: +7:34
         _14 = &_15;                      // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-        Retag(_14);                      // 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
         _35 = const _;                   // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
                                          // mir::Constant
@@ -127,7 +122,6 @@ fn array_casts() -> () {
                                          // + literal: Const { ty: &usize, val: Unevaluated(array_casts, [], Some(promoted[0])) }
         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
         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
@@ -151,7 +145,7 @@ fn array_casts() -> () {
         StorageDead(_24);                // scope 7 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
         _22 = Not(move _23);             // scope 7 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
         StorageDead(_23);                // scope 7 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-        switchInt(move _22) -> [false: bb4, otherwise: bb3]; // scope 7 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+        switchInt(move _22) -> [0: bb4, otherwise: bb3]; // scope 7 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
     }
 
     bb3: {
@@ -164,15 +158,11 @@ fn array_casts() -> () {
         StorageLive(_30);                // scope 8 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
         StorageLive(_31);                // scope 8 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
         _31 = &(*_20);                   // scope 8 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-        Retag(_31);                      // scope 8 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
         _30 = &(*_31);                   // scope 8 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-        Retag(_30);                      // scope 8 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
         StorageLive(_32);                // scope 8 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
         StorageLive(_33);                // scope 8 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
         _33 = &(*_21);                   // scope 8 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-        Retag(_33);                      // scope 8 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
         _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
         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
index cdc413c568f184c485e83c6d6143ec741493f1ce..14f297e948bec91b29791e7fce4c216c06c76458 100644 (file)
@@ -6,7 +6,6 @@ fn std::ptr::drop_in_place(_1: *mut Test) -> () {
     let mut _3: ();                      // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
 
     bb0: {
-        Retag([raw] _1);                 // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
         _2 = &mut (*_1);                 // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
         _3 = <Test as Drop>::drop(move _2) -> bb1; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
                                          // mir::Constant
index 96fc7e6493ab94dc7e19a5e503c4bcd87791ef01..9e5c119a2b24e3300dcca541b860c806c37efe34 100644 (file)
@@ -15,7 +15,6 @@ fn main::{closure#0}(_1: &[closure@main::{closure#0}], _2: &i32) -> &i32 {
         _3 = _2;                         // scope 0 at $DIR/retag.rs:+1:18: +1:19
         Retag(_3);                       // scope 0 at $DIR/retag.rs:+1:18: +1:19
         _0 = &(*_2);                     // scope 1 at $DIR/retag.rs:+2:9: +2:10
-        Retag(_0);                       // scope 1 at $DIR/retag.rs:+2:9: +2:10
         StorageDead(_3);                 // scope 0 at $DIR/retag.rs:+3:5: +3:6
         return;                          // scope 0 at $DIR/retag.rs:+3:6: +3:6
     }
index 81225b44ebf9fd5d572e1d250ef6e3cfd46f068f..b853e450541729d82ad1b577e63cd67309746209 100644 (file)
@@ -65,13 +65,10 @@ fn main() -> () {
         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
         StorageLive(_7);                 // scope 1 at $DIR/retag.rs:+3:29: +3:35
         _7 = &mut _1;                    // scope 1 at $DIR/retag.rs:+3:29: +3:35
-        Retag(_7);                       // scope 1 at $DIR/retag.rs:+3:29: +3:35
         _6 = &mut (*_7);                 // scope 1 at $DIR/retag.rs:+3:29: +3:35
-        Retag([2phase] _6);              // scope 1 at $DIR/retag.rs:+3:29: +3:35
         _3 = Test::foo(move _4, move _6) -> [return: bb1, unwind: bb8]; // scope 1 at $DIR/retag.rs:+3:17: +3:36
                                          // mir::Constant
                                          // + span: $DIR/retag.rs:33:25: 33:28
@@ -93,7 +90,6 @@ fn main() -> () {
         _9 = move _3;                    // scope 2 at $DIR/retag.rs:+4:19: +4:20
         Retag(_9);                       // scope 2 at $DIR/retag.rs:+4:19: +4:20
         _8 = &mut (*_9);                 // scope 2 at $DIR/retag.rs:+4:19: +4:20
-        Retag(_8);                       // scope 2 at $DIR/retag.rs:+4:19: +4:20
         StorageDead(_9);                 // scope 2 at $DIR/retag.rs:+4:22: +4:23
         StorageLive(_10);                // scope 3 at $DIR/retag.rs:+5:13: +5:14
         _10 = move _8;                   // scope 3 at $DIR/retag.rs:+5:17: +5:18
@@ -101,7 +97,6 @@ fn main() -> () {
         StorageLive(_11);                // scope 4 at $DIR/retag.rs:+7:13: +7:15
         StorageLive(_12);                // scope 4 at $DIR/retag.rs:+7:18: +7:29
         _12 = &raw mut (*_10);           // scope 4 at $DIR/retag.rs:+7:18: +7:19
-        Retag([raw] _12);                // scope 4 at $DIR/retag.rs:+7:18: +7:19
         _11 = _12;                       // scope 4 at $DIR/retag.rs:+7:18: +7:29
         StorageDead(_12);                // scope 4 at $DIR/retag.rs:+7:29: +7:30
         _2 = const ();                   // scope 1 at $DIR/retag.rs:+2:5: +8:6
@@ -122,9 +117,7 @@ fn main() -> () {
         StorageLive(_17);                // scope 6 at $DIR/retag.rs:+15:16: +15:18
         StorageLive(_18);                // scope 6 at $DIR/retag.rs:+15:16: +15:18
         _18 = &_1;                       // scope 6 at $DIR/retag.rs:+15:16: +15:18
-        Retag(_18);                      // scope 6 at $DIR/retag.rs:+15:16: +15:18
         _17 = &(*_18);                   // scope 6 at $DIR/retag.rs:+15:16: +15:18
-        Retag(_17);                      // scope 6 at $DIR/retag.rs:+15:16: +15:18
         _15 = move _16(move _17) -> bb3; // scope 6 at $DIR/retag.rs:+15:14: +15:19
     }
 
@@ -139,7 +132,6 @@ fn main() -> () {
         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
         StorageLive(_23);                // scope 7 at $DIR/retag.rs:+18:21: +18:23
         _28 = const _;                   // scope 7 at $DIR/retag.rs:+18:21: +18:23
@@ -148,9 +140,7 @@ fn main() -> () {
                                          // + literal: Const { ty: &i32, val: Unevaluated(main, [], Some(promoted[0])) }
         Retag(_28);                      // scope 7 at $DIR/retag.rs:+18:21: +18:23
         _23 = &(*_28);                   // scope 7 at $DIR/retag.rs:+18:21: +18:23
-        Retag(_23);                      // scope 7 at $DIR/retag.rs:+18:21: +18:23
         _22 = &(*_23);                   // scope 7 at $DIR/retag.rs:+18:21: +18:23
-        Retag(_22);                      // scope 7 at $DIR/retag.rs:+18:21: +18:23
         _19 = Test::foo_shr(move _20, move _22) -> [return: bb4, unwind: bb7]; // scope 7 at $DIR/retag.rs:+18:5: +18:24
                                          // mir::Constant
                                          // + span: $DIR/retag.rs:48:13: 48:20
@@ -171,7 +161,6 @@ fn main() -> () {
         StorageLive(_25);                // scope 7 at $DIR/retag.rs:+21:9: +21:11
         StorageLive(_26);                // scope 7 at $DIR/retag.rs:+21:14: +21:28
         _26 = &raw const (*_15);         // scope 7 at $DIR/retag.rs:+21:14: +21:16
-        Retag([raw] _26);                // scope 7 at $DIR/retag.rs:+21:14: +21:16
         _25 = _26;                       // scope 7 at $DIR/retag.rs:+21:14: +21:28
         StorageDead(_26);                // scope 7 at $DIR/retag.rs:+21:28: +21:29
         StorageLive(_27);                // scope 8 at $DIR/retag.rs:+23:5: +23:18
index 08fd655ae29bb979f6161bc63c8886cadee45b50..4b50205fa8081ce7e284517a96d9c43f4a013bef 100644 (file)
@@ -11,9 +11,7 @@ fn <impl at $DIR/retag.rs:12:1: 12:10>::foo(_1: &Test, _2: &mut i32) -> &mut i32
         Retag([fn entry] _2);            // scope 0 at $DIR/retag.rs:+0:23: +0:24
         StorageLive(_3);                 // scope 0 at $DIR/retag.rs:+1:9: +1:10
         _3 = &mut (*_2);                 // scope 0 at $DIR/retag.rs:+1:9: +1:10
-        Retag(_3);                       // scope 0 at $DIR/retag.rs:+1:9: +1:10
         _0 = &mut (*_3);                 // scope 0 at $DIR/retag.rs:+1:9: +1:10
-        Retag(_0);                       // scope 0 at $DIR/retag.rs:+1:9: +1:10
         StorageDead(_3);                 // scope 0 at $DIR/retag.rs:+2:5: +2:6
         return;                          // scope 0 at $DIR/retag.rs:+2:6: +2:6
     }
index f25b3ce724be2db89b3f95fff98746d059aaaa80..6ae16bdb5b88a6b673807d83b9a32fedf2c0b6c6 100644 (file)
@@ -22,9 +22,6 @@
                   let mut _18: i32;        // in scope 8 at $SRC_DIR/core/src/result.rs:LL:COL
                   scope 9 {
                       debug e => _16;      // in scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
-                      scope 10 (inlined <i32 as From<i32>>::from) { // at $SRC_DIR/core/src/result.rs:LL:COL
-                          debug t => _18;  // in scope 10 at $SRC_DIR/core/src/convert/mod.rs:LL:COL
-                      }
                   }
               }
           }
           StorageLive(_4);                 // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:9
           _4 = _1;                         // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:9
           _10 = discriminant(_4);          // scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
--         switchInt(move _10) -> [0_isize: bb7, 1_isize: bb5, otherwise: bb6]; // scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
-+         switchInt(move _10) -> [0_isize: bb6, 1_isize: bb4, otherwise: bb5]; // scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
+-         switchInt(move _10) -> [0: bb7, 1: bb5, otherwise: bb6]; // scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
++         switchInt(move _10) -> [0: bb6, 1: bb4, otherwise: bb5]; // scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
       }
   
       bb1: {
 -         StorageDead(_4);                 // scope 0 at $DIR/separate_const_switch.rs:+1:9: +1:10
 -         _5 = discriminant(_3);           // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10
--         switchInt(move _5) -> [0_isize: bb2, 1_isize: bb4, otherwise: bb3]; // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10
+-         switchInt(move _5) -> [0: bb2, 1: bb4, otherwise: bb3]; // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10
 -     }
 - 
 -     bb2: {
           StorageLive(_17);                // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
           StorageLive(_18);                // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
           _18 = move _16;                  // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
-          _17 = move _18;                  // scope 10 at $SRC_DIR/core/src/convert/mod.rs:LL:COL
-          StorageDead(_18);                // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
-          Deinit(_0);                      // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
-          ((_0 as Err).0: i32) = move _17; // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
-          discriminant(_0) = 1;            // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
-          StorageDead(_17);                // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
-          StorageDead(_16);                // scope 8 at $SRC_DIR/core/src/result.rs:LL:COL
-          StorageDead(_8);                 // scope 2 at $DIR/separate_const_switch.rs:+1:9: +1:10
-          StorageDead(_6);                 // scope 0 at $DIR/separate_const_switch.rs:+1:9: +1:10
-          StorageDead(_2);                 // scope 0 at $DIR/separate_const_switch.rs:+1:10: +1:11
-          StorageDead(_3);                 // scope 0 at $DIR/separate_const_switch.rs:+2:1: +2:2
-          return;                          // scope 0 at $DIR/separate_const_switch.rs:+2:2: +2:2
+-         _17 = <i32 as From<i32>>::from(move _18) -> bb8; // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
++         _17 = <i32 as From<i32>>::from(move _18) -> bb7; // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
+                                           // mir::Constant
+                                           // + span: $SRC_DIR/core/src/result.rs:LL:COL
+                                           // + literal: Const { ty: fn(i32) -> i32 {<i32 as From<i32>>::from}, val: Value(<ZST>) }
       }
   
 -     bb5: {
 -         goto -> bb1;                     // scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
 +         StorageDead(_4);                 // scope 0 at $DIR/separate_const_switch.rs:+1:9: +1:10
 +         _5 = discriminant(_3);           // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10
-+         switchInt(move _5) -> [0_isize: bb1, 1_isize: bb3, otherwise: bb2]; // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10
++         switchInt(move _5) -> [0: bb1, 1: bb3, otherwise: bb2]; // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10
       }
   
 -     bb6: {
 -         goto -> bb1;                     // scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
 +         StorageDead(_4);                 // scope 0 at $DIR/separate_const_switch.rs:+1:9: +1:10
 +         _5 = discriminant(_3);           // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10
-+         switchInt(move _5) -> [0_isize: bb1, 1_isize: bb3, otherwise: bb2]; // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10
++         switchInt(move _5) -> [0: bb1, 1: bb3, otherwise: bb2]; // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10
+      }
+  
+-     bb8: {
++     bb7: {
+          StorageDead(_18);                // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
+          Deinit(_0);                      // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
+          ((_0 as Err).0: i32) = move _17; // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
+          discriminant(_0) = 1;            // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
+          StorageDead(_17);                // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
+          StorageDead(_16);                // scope 8 at $SRC_DIR/core/src/result.rs:LL:COL
+          StorageDead(_8);                 // scope 2 at $DIR/separate_const_switch.rs:+1:9: +1:10
+          StorageDead(_6);                 // scope 0 at $DIR/separate_const_switch.rs:+1:9: +1:10
+          StorageDead(_2);                 // scope 0 at $DIR/separate_const_switch.rs:+1:10: +1:11
+          StorageDead(_3);                 // scope 0 at $DIR/separate_const_switch.rs:+2:1: +2:2
+          return;                          // scope 0 at $DIR/separate_const_switch.rs:+2:2: +2:2
       }
   }
   
index 437979081367a1bc26cc9fa565bac77fcf25104b..8cc0c6a18353c2b8ea33f0c5c25d065a6b1a0ff2 100644 (file)
@@ -30,7 +30,7 @@
       bb0: {
           StorageLive(_2);                 // scope 0 at $DIR/separate_const_switch.rs:+5:11: +10:6
           _3 = discriminant(_1);           // scope 0 at $DIR/separate_const_switch.rs:+6:15: +6:16
-          switchInt(move _3) -> [0_isize: bb3, 1_isize: bb1, otherwise: bb2]; // scope 0 at $DIR/separate_const_switch.rs:+6:9: +6:16
+          switchInt(move _3) -> [0: bb3, 1: bb1, otherwise: bb2]; // scope 0 at $DIR/separate_const_switch.rs:+6:9: +6:16
       }
   
       bb1: {
@@ -45,7 +45,7 @@
           StorageDead(_6);                 // scope 0 at $DIR/separate_const_switch.rs:+8:43: +8:44
 -         goto -> bb4;                     // scope 0 at $DIR/separate_const_switch.rs:+8:43: +8:44
 +         _8 = discriminant(_2);           // scope 0 at $DIR/separate_const_switch.rs:+5:11: +10:6
-+         switchInt(move _8) -> [0_isize: bb6, 1_isize: bb4, otherwise: bb5]; // scope 0 at $DIR/separate_const_switch.rs:+5:5: +10:6
++         switchInt(move _8) -> [0: bb6, 1: bb4, otherwise: bb5]; // scope 0 at $DIR/separate_const_switch.rs:+5:5: +10:6
       }
   
       bb2: {
@@ -67,8 +67,8 @@
 - 
 -     bb4: {
           _8 = discriminant(_2);           // scope 0 at $DIR/separate_const_switch.rs:+5:11: +10:6
--         switchInt(move _8) -> [0_isize: bb7, 1_isize: bb5, otherwise: bb6]; // scope 0 at $DIR/separate_const_switch.rs:+5:5: +10:6
-+         switchInt(move _8) -> [0_isize: bb6, 1_isize: bb4, otherwise: bb5]; // scope 0 at $DIR/separate_const_switch.rs:+5:5: +10:6
+-         switchInt(move _8) -> [0: bb7, 1: bb5, otherwise: bb6]; // scope 0 at $DIR/separate_const_switch.rs:+5:5: +10:6
++         switchInt(move _8) -> [0: bb6, 1: bb4, otherwise: bb5]; // scope 0 at $DIR/separate_const_switch.rs:+5:5: +10:6
       }
   
 -     bb5: {
index e068b81bc3bc2f8d5b1c906fbc036c42efe3435c..8eb1aa1f3b3d0cf85b697f543aa937b6aad37f9d 100644 (file)
@@ -25,9 +25,9 @@
       }
   
 -     bb3: {
--         switchInt(move _2) -> [false: bb5, otherwise: bb4]; // scope 0 at $DIR/simplify_cfg.rs:+2:12: +2:17
+-         switchInt(move _2) -> [0: bb5, otherwise: bb4]; // scope 0 at $DIR/simplify_cfg.rs:+2:12: +2:17
 +     bb2: {
-+         switchInt(move _2) -> [false: bb4, otherwise: bb3]; // scope 0 at $DIR/simplify_cfg.rs:+2:12: +2:17
++         switchInt(move _2) -> [0: bb4, otherwise: bb3]; // scope 0 at $DIR/simplify_cfg.rs:+2:12: +2:17
       }
   
 -     bb4: {
index f693798eb942d3dc177dd10c0f6637f9e42e91d8..1e66b1f703e3fea1d8bd151d44b25e8239460f10 100644 (file)
@@ -26,7 +26,7 @@
       }
   
       bb3: {
-          switchInt(move _2) -> [false: bb5, otherwise: bb4]; // scope 0 at $DIR/simplify_cfg.rs:+2:12: +2:17
+          switchInt(move _2) -> [0: bb5, otherwise: bb4]; // scope 0 at $DIR/simplify_cfg.rs:+2:12: +2:17
       }
   
       bb4: {
index 9b1bea2704b7771d78e66262746755337499d1ee..aea0114744352d0b7a2af771f2cdc8db318a670d 100644 (file)
@@ -9,7 +9,7 @@
       bb0: {
           StorageLive(_1);                 // scope 0 at $DIR/simplify_if.rs:+1:8: +1:13
           _1 = const false;                // scope 0 at $DIR/simplify_if.rs:+1:8: +1:13
--         switchInt(const false) -> [false: bb3, otherwise: bb1]; // scope 0 at $DIR/simplify_if.rs:+1:8: +1:13
+-         switchInt(const false) -> [0: bb3, otherwise: bb1]; // scope 0 at $DIR/simplify_if.rs:+1:8: +1:13
 +         goto -> bb3;                     // scope 0 at $DIR/simplify_if.rs:+1:8: +1:13
       }
   
index 8feddcef2ceefe67ec2ed32ac8db97b3ddb17827..a2b55229303d39446a364aadbf2e0025cb202825 100644 (file)
           StorageDead(_3);                 // scope 1 at $DIR/simplify_locals_fixedpoint.rs:+1:68: +1:69
           StorageDead(_2);                 // scope 1 at $DIR/simplify_locals_fixedpoint.rs:+1:68: +1:69
           _5 = discriminant((_1.0: std::option::Option<u8>)); // scope 1 at $DIR/simplify_locals_fixedpoint.rs:+1:12: +1:27
-          switchInt(move _5) -> [1_isize: bb1, otherwise: bb3]; // scope 1 at $DIR/simplify_locals_fixedpoint.rs:+1:12: +1:27
+          switchInt(move _5) -> [1: bb1, otherwise: bb3]; // scope 1 at $DIR/simplify_locals_fixedpoint.rs:+1:12: +1:27
       }
   
       bb1: {
           _4 = discriminant((_1.1: std::option::Option<T>)); // scope 1 at $DIR/simplify_locals_fixedpoint.rs:+1:12: +1:27
-          switchInt(move _4) -> [0_isize: bb2, otherwise: bb3]; // scope 1 at $DIR/simplify_locals_fixedpoint.rs:+1:12: +1:27
+          switchInt(move _4) -> [0: bb2, otherwise: bb3]; // scope 1 at $DIR/simplify_locals_fixedpoint.rs:+1:12: +1:27
       }
   
       bb2: {
index 6e7294003afae8e5eb09590912f0229cbb8b6f35..9ec138dd82f44b43230b458e4f785038b6d45e92 100644 (file)
@@ -18,7 +18,7 @@
 -         _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
+          switchInt(move _2) -> [0: bb3, 1: bb1, otherwise: bb2]; // scope 0 at $DIR/simplify_locals_removes_unused_discriminant_reads.rs:+1:5: +1:12
       }
   
       bb1: {
index e4f9a4c12d9cb43a0a2f3bd0b0aeb54138ce31d2..f00ac5716a7517c7b29f56dc48688ca8ee37784e 100644 (file)
@@ -16,8 +16,8 @@
 -         _1 = _2;                         // scope 1 at $DIR/simplify_match.rs:+1:28: +1:29
 +         _1 = const false;                // scope 1 at $DIR/simplify_match.rs:+1:28: +1:29
           StorageDead(_2);                 // scope 0 at $DIR/simplify_match.rs:+1:30: +1:31
--         switchInt(_1) -> [false: bb1, otherwise: bb2]; // scope 0 at $DIR/simplify_match.rs:+1:5: +1:31
-+         switchInt(const false) -> [false: bb1, otherwise: bb2]; // scope 0 at $DIR/simplify_match.rs:+1:5: +1:31
+-         switchInt(_1) -> [0: bb1, otherwise: bb2]; // scope 0 at $DIR/simplify_match.rs:+1:5: +1:31
++         switchInt(const false) -> [0: bb1, otherwise: bb2]; // scope 0 at $DIR/simplify_match.rs:+1:5: +1:31
       }
   
       bb1: {
index 31ccf14549ca21637c82ab8dd8f0578bb05982c7..391b00effacfa0577a60e22008770449fab227a6 100644 (file)
@@ -37,7 +37,7 @@ fn std::ptr::drop_in_place(_1: *mut [String]) -> () {
 
     bb4 (cleanup): {
         _6 = Eq(_4, _3);                 // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-        switchInt(move _6) -> [false: bb3, otherwise: bb2]; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
+        switchInt(move _6) -> [0: bb3, otherwise: bb2]; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
     }
 
     bb5: {
@@ -48,7 +48,7 @@ fn std::ptr::drop_in_place(_1: *mut [String]) -> () {
 
     bb6: {
         _8 = Eq(_4, _3);                 // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-        switchInt(move _8) -> [false: bb5, otherwise: bb1]; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
+        switchInt(move _8) -> [0: bb5, otherwise: bb1]; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
     }
 
     bb7: {
@@ -68,7 +68,7 @@ fn std::ptr::drop_in_place(_1: *mut [String]) -> () {
 
     bb10 (cleanup): {
         _12 = Eq(_9, _10);               // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-        switchInt(move _12) -> [false: bb9, otherwise: bb2]; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
+        switchInt(move _12) -> [0: bb9, otherwise: bb2]; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
     }
 
     bb11: {
@@ -79,7 +79,7 @@ fn std::ptr::drop_in_place(_1: *mut [String]) -> () {
 
     bb12: {
         _14 = Eq(_9, _10);               // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-        switchInt(move _14) -> [false: bb11, otherwise: bb1]; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
+        switchInt(move _14) -> [0: bb11, otherwise: bb1]; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
     }
 
     bb13: {
@@ -96,6 +96,6 @@ fn std::ptr::drop_in_place(_1: *mut [String]) -> () {
     bb15: {
         _2 = SizeOf(std::string::String); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
         _3 = Len((*_1));                 // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-        switchInt(move _2) -> [0_usize: bb8, otherwise: bb14]; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
+        switchInt(move _2) -> [0: bb8, otherwise: bb14]; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
     }
 }
index 7c7e87c32a2d311858a93168a5ab864e98b1394e..a5488c1ec7bfee1f31c4ae7fc8d7ab3331b345ab 100644 (file)
@@ -21,7 +21,7 @@
           discriminant(_2) = 1;            // scope 1 at $DIR/sroa.rs:+1:22: +1:29
           StorageDead(_3);                 // scope 1 at $DIR/sroa.rs:+1:28: +1:29
           _4 = discriminant(_2);           // scope 1 at $DIR/sroa.rs:+1:12: +1:19
-          switchInt(move _4) -> [1_isize: bb1, otherwise: bb2]; // scope 1 at $DIR/sroa.rs:+1:12: +1:19
+          switchInt(move _4) -> [1: bb1, otherwise: bb2]; // scope 1 at $DIR/sroa.rs:+1:12: +1:19
       }
   
       bb1: {
index 30185f3ffab29ab55a634ce5eaec34e5ace56b52..b254bfeb7c992500212de9570d51fd6ae98b8dbc 100644 (file)
@@ -26,7 +26,7 @@ fn new(_1: Result<T, E>) -> Result<T, E> {
     bb0: {
         StorageLive(_2);                 // scope 0 at $DIR/try_identity_e2e.rs:+2:15: +7:10
         _3 = discriminant(_1);           // scope 0 at $DIR/try_identity_e2e.rs:+3:19: +3:20
-        switchInt(move _3) -> [0_isize: bb2, 1_isize: bb1, otherwise: bb4]; // scope 0 at $DIR/try_identity_e2e.rs:+3:13: +3:20
+        switchInt(move _3) -> [0: bb2, 1: bb1, otherwise: bb4]; // scope 0 at $DIR/try_identity_e2e.rs:+3:13: +3:20
     }
 
     bb1: {
@@ -35,7 +35,7 @@ fn new(_1: Result<T, E>) -> Result<T, E> {
         ((_2 as Break).0: E) = move _5;  // scope 2 at $DIR/try_identity_e2e.rs:+5:27: +5:48
         discriminant(_2) = 1;            // scope 2 at $DIR/try_identity_e2e.rs:+5:27: +5:48
         _6 = discriminant(_2);           // scope 0 at $DIR/try_identity_e2e.rs:+2:15: +7:10
-        switchInt(move _6) -> [0_isize: bb5, 1_isize: bb3, otherwise: bb4]; // scope 0 at $DIR/try_identity_e2e.rs:+2:9: +7:10
+        switchInt(move _6) -> [0: bb5, 1: bb3, otherwise: bb4]; // scope 0 at $DIR/try_identity_e2e.rs:+2:9: +7:10
     }
 
     bb2: {
@@ -44,7 +44,7 @@ fn new(_1: Result<T, E>) -> Result<T, E> {
         ((_2 as Continue).0: T) = move _4; // scope 1 at $DIR/try_identity_e2e.rs:+4:26: +4:50
         discriminant(_2) = 0;            // scope 1 at $DIR/try_identity_e2e.rs:+4:26: +4:50
         _6 = discriminant(_2);           // scope 0 at $DIR/try_identity_e2e.rs:+2:15: +7:10
-        switchInt(move _6) -> [0_isize: bb5, 1_isize: bb3, otherwise: bb4]; // scope 0 at $DIR/try_identity_e2e.rs:+2:9: +7:10
+        switchInt(move _6) -> [0: bb5, 1: bb3, otherwise: bb4]; // scope 0 at $DIR/try_identity_e2e.rs:+2:9: +7:10
     }
 
     bb3: {
index 2a9c7408c66eb4a36bb7181df80d4cf8d01000f8..cdbc0681cb8a363ae2acadeeb236c7718ad3c00a 100644 (file)
@@ -15,7 +15,7 @@ fn old(_1: Result<T, E>) -> Result<T, E> {
 
     bb0: {
         _2 = discriminant(_1);           // scope 0 at $DIR/try_identity_e2e.rs:+2:15: +2:16
-        switchInt(move _2) -> [0_isize: bb3, 1_isize: bb1, otherwise: bb2]; // scope 0 at $DIR/try_identity_e2e.rs:+2:9: +2:16
+        switchInt(move _2) -> [0: bb3, 1: bb1, otherwise: bb2]; // scope 0 at $DIR/try_identity_e2e.rs:+2:9: +2:16
     }
 
     bb1: {
index 4aa5ba007f11937b6fbfb2fb9fc6b9a9e03fd255..39ec05277595518ba60e39de7973cdbb8b998c71 100644 (file)
@@ -18,7 +18,7 @@ fn main() -> () {
         Deinit(_2);                      // scope 0 at $DIR/uninhabited_enum_branching.rs:+1:11: +1:19
         discriminant(_2) = 2;            // scope 0 at $DIR/uninhabited_enum_branching.rs:+1:11: +1:19
         _3 = discriminant(_2);           // scope 0 at $DIR/uninhabited_enum_branching.rs:+1:11: +1:19
-        switchInt(move _3) -> [2_isize: bb1, otherwise: bb2]; // scope 0 at $DIR/uninhabited_enum_branching.rs:+1:5: +1:19
+        switchInt(move _3) -> [2: bb1, otherwise: bb2]; // scope 0 at $DIR/uninhabited_enum_branching.rs:+1:5: +1:19
     }
 
     bb1: {
@@ -36,7 +36,7 @@ fn main() -> () {
         Deinit(_7);                      // scope 0 at $DIR/uninhabited_enum_branching.rs:+7:11: +7:19
         discriminant(_7) = 0;            // scope 0 at $DIR/uninhabited_enum_branching.rs:+7:11: +7:19
         _8 = discriminant(_7);           // scope 0 at $DIR/uninhabited_enum_branching.rs:+7:11: +7:19
-        switchInt(move _8) -> [4_isize: bb5, 5_isize: bb3, otherwise: bb4]; // scope 0 at $DIR/uninhabited_enum_branching.rs:+7:5: +7:19
+        switchInt(move _8) -> [4: bb5, 5: bb3, otherwise: bb4]; // scope 0 at $DIR/uninhabited_enum_branching.rs:+7:5: +7:19
     }
 
     bb2: {
index c3d356aedb28176cdf145143d968b26da0ac166b..598413a1d82de896744266987d7f71afe96793b8 100644 (file)
@@ -19,8 +19,8 @@
           Deinit(_2);                      // scope 0 at $DIR/uninhabited_enum_branching.rs:+1:11: +1:19
           discriminant(_2) = 2;            // scope 0 at $DIR/uninhabited_enum_branching.rs:+1:11: +1:19
           _3 = discriminant(_2);           // scope 0 at $DIR/uninhabited_enum_branching.rs:+1:11: +1:19
--         switchInt(move _3) -> [0_isize: bb3, 1_isize: bb4, 2_isize: bb1, otherwise: bb2]; // scope 0 at $DIR/uninhabited_enum_branching.rs:+1:5: +1:19
-+         switchInt(move _3) -> [2_isize: bb1, otherwise: bb2]; // scope 0 at $DIR/uninhabited_enum_branching.rs:+1:5: +1:19
+-         switchInt(move _3) -> [0: bb3, 1: bb4, 2: bb1, otherwise: bb2]; // scope 0 at $DIR/uninhabited_enum_branching.rs:+1:5: +1:19
++         switchInt(move _3) -> [2: bb1, otherwise: bb2]; // scope 0 at $DIR/uninhabited_enum_branching.rs:+1:5: +1:19
       }
   
       bb1: {
@@ -65,7 +65,7 @@
           Deinit(_7);                      // scope 0 at $DIR/uninhabited_enum_branching.rs:+7:11: +7:19
           discriminant(_7) = 0;            // scope 0 at $DIR/uninhabited_enum_branching.rs:+7:11: +7:19
           _8 = discriminant(_7);           // scope 0 at $DIR/uninhabited_enum_branching.rs:+7:11: +7:19
-          switchInt(move _8) -> [4_isize: bb8, 5_isize: bb6, otherwise: bb7]; // scope 0 at $DIR/uninhabited_enum_branching.rs:+7:5: +7:19
+          switchInt(move _8) -> [4: bb8, 5: bb6, otherwise: bb7]; // scope 0 at $DIR/uninhabited_enum_branching.rs:+7:5: +7:19
       }
   
       bb6: {
index ec5612ad76790d5619dcba69a2b3d0797f7b108f..c8cd6f6c1ea1d69950ee8f65accd39fb1acdaf6f 100644 (file)
@@ -32,7 +32,7 @@ fn main() -> () {
         StorageLive(_4);                 // scope 1 at $DIR/uninhabited_enum_branching2.rs:+3:11: +3:22
         _4 = &(_1.1: Test1);             // scope 1 at $DIR/uninhabited_enum_branching2.rs:+3:11: +3:22
         _5 = discriminant((*_4));        // scope 1 at $DIR/uninhabited_enum_branching2.rs:+3:11: +3:22
-        switchInt(move _5) -> [2_isize: bb3, 3_isize: bb1, otherwise: bb2]; // scope 1 at $DIR/uninhabited_enum_branching2.rs:+3:5: +3:22
+        switchInt(move _5) -> [2: bb3, 3: bb1, otherwise: bb2]; // scope 1 at $DIR/uninhabited_enum_branching2.rs:+3:5: +3:22
     }
 
     bb1: {
@@ -66,7 +66,7 @@ fn main() -> () {
         StorageDead(_3);                 // scope 1 at $DIR/uninhabited_enum_branching2.rs:+8:6: +8:7
         StorageLive(_9);                 // scope 1 at $DIR/uninhabited_enum_branching2.rs:+10:5: +15:6
         _10 = discriminant((_1.1: Test1)); // scope 1 at $DIR/uninhabited_enum_branching2.rs:+10:11: +10:21
-        switchInt(move _10) -> [2_isize: bb7, 3_isize: bb5, otherwise: bb6]; // scope 1 at $DIR/uninhabited_enum_branching2.rs:+10:5: +10:21
+        switchInt(move _10) -> [2: bb7, 3: bb5, otherwise: bb6]; // scope 1 at $DIR/uninhabited_enum_branching2.rs:+10:5: +10:21
     }
 
     bb5: {
index 77b358a4801e5b7870c8f3424f87270325d03bee..2aee6d2681d642466be5cab4bb5b8b93da629ea4 100644 (file)
@@ -33,8 +33,8 @@
           StorageLive(_4);                 // scope 1 at $DIR/uninhabited_enum_branching2.rs:+3:11: +3:22
           _4 = &(_1.1: Test1);             // scope 1 at $DIR/uninhabited_enum_branching2.rs:+3:11: +3:22
           _5 = discriminant((*_4));        // scope 1 at $DIR/uninhabited_enum_branching2.rs:+3:11: +3:22
--         switchInt(move _5) -> [0_isize: bb3, 1_isize: bb4, 2_isize: bb5, 3_isize: bb1, otherwise: bb2]; // scope 1 at $DIR/uninhabited_enum_branching2.rs:+3:5: +3:22
-+         switchInt(move _5) -> [2_isize: bb5, 3_isize: bb1, otherwise: bb2]; // scope 1 at $DIR/uninhabited_enum_branching2.rs:+3:5: +3:22
+-         switchInt(move _5) -> [0: bb3, 1: bb4, 2: bb5, 3: bb1, otherwise: bb2]; // scope 1 at $DIR/uninhabited_enum_branching2.rs:+3:5: +3:22
++         switchInt(move _5) -> [2: bb5, 3: bb1, otherwise: bb2]; // scope 1 at $DIR/uninhabited_enum_branching2.rs:+3:5: +3:22
       }
   
       bb1: {
@@ -87,8 +87,8 @@
           StorageDead(_3);                 // scope 1 at $DIR/uninhabited_enum_branching2.rs:+8:6: +8:7
           StorageLive(_9);                 // scope 1 at $DIR/uninhabited_enum_branching2.rs:+10:5: +15:6
           _10 = discriminant((_1.1: Test1)); // scope 1 at $DIR/uninhabited_enum_branching2.rs:+10:11: +10:21
--         switchInt(move _10) -> [0_isize: bb9, 1_isize: bb10, 2_isize: bb11, 3_isize: bb7, otherwise: bb8]; // scope 1 at $DIR/uninhabited_enum_branching2.rs:+10:5: +10:21
-+         switchInt(move _10) -> [2_isize: bb11, 3_isize: bb7, otherwise: bb8]; // scope 1 at $DIR/uninhabited_enum_branching2.rs:+10:5: +10:21
+-         switchInt(move _10) -> [0: bb9, 1: bb10, 2: bb11, 3: bb7, otherwise: bb8]; // scope 1 at $DIR/uninhabited_enum_branching2.rs:+10:5: +10:21
++         switchInt(move _10) -> [2: bb11, 3: bb7, otherwise: bb8]; // scope 1 at $DIR/uninhabited_enum_branching2.rs:+10:5: +10:21
       }
   
       bb7: {
index 11d93fca7e0866cf33a1c16bbd9ce9dcab4ff8ec..58e085dd041972089317a9e7964b4ea9c64c0107 100644 (file)
@@ -8,8 +8,8 @@
   
       bb0: {
           _2 = discriminant(_1);           // scope 0 at $DIR/uninhabited_fallthrough_elimination.rs:+1:11: +1:12
--         switchInt(move _2) -> [1_isize: bb3, 2_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/uninhabited_fallthrough_elimination.rs:+1:5: +1:12
-+         switchInt(move _2) -> [1_isize: bb3, 2_isize: bb2, otherwise: bb5]; // scope 0 at $DIR/uninhabited_fallthrough_elimination.rs:+1:5: +1:12
+-         switchInt(move _2) -> [1: bb3, 2: bb2, otherwise: bb1]; // scope 0 at $DIR/uninhabited_fallthrough_elimination.rs:+1:5: +1:12
++         switchInt(move _2) -> [1: bb3, 2: bb2, otherwise: bb5]; // scope 0 at $DIR/uninhabited_fallthrough_elimination.rs:+1:5: +1:12
       }
   
       bb1: {
index a7f8321ae34bac4c6dab3392bd7cedcceab3486f..e765851eb78b7a75d50d871407ce6e196744ec57 100644 (file)
@@ -8,8 +8,8 @@
   
       bb0: {
           _2 = discriminant(_1);           // scope 0 at $DIR/uninhabited_fallthrough_elimination.rs:+1:11: +1:12
--         switchInt(move _2) -> [0_isize: bb2, 1_isize: bb3, otherwise: bb1]; // scope 0 at $DIR/uninhabited_fallthrough_elimination.rs:+1:5: +1:12
-+         switchInt(move _2) -> [1_isize: bb3, otherwise: bb1]; // scope 0 at $DIR/uninhabited_fallthrough_elimination.rs:+1:5: +1:12
+-         switchInt(move _2) -> [0: bb2, 1: bb3, otherwise: bb1]; // scope 0 at $DIR/uninhabited_fallthrough_elimination.rs:+1:5: +1:12
++         switchInt(move _2) -> [1: bb3, otherwise: bb1]; // scope 0 at $DIR/uninhabited_fallthrough_elimination.rs:+1:5: +1:12
       }
   
       bb1: {
index 9cd4b8ccf331abe00c198e09b85b3feae81d2aa5..848bff1d4920c18695bb801134b4d80c0b90b75c 100644 (file)
@@ -27,8 +27,8 @@
   
       bb1: {
           _2 = discriminant(_1);           // scope 1 at $DIR/unreachable.rs:+1:12: +1:20
--         switchInt(move _2) -> [1_isize: bb2, otherwise: bb6]; // scope 1 at $DIR/unreachable.rs:+1:12: +1:20
-+         switchInt(move _2) -> [1_isize: bb2, otherwise: bb3]; // scope 1 at $DIR/unreachable.rs:+1:12: +1:20
+-         switchInt(move _2) -> [1: bb2, otherwise: bb6]; // scope 1 at $DIR/unreachable.rs:+1:12: +1:20
++         switchInt(move _2) -> [1: bb2, otherwise: bb3]; // scope 1 at $DIR/unreachable.rs:+1:12: +1:20
       }
   
       bb2: {
@@ -38,7 +38,7 @@
 -         StorageLive(_5);                 // scope 2 at $DIR/unreachable.rs:+4:9: +8:10
 -         StorageLive(_6);                 // scope 2 at $DIR/unreachable.rs:+4:12: +4:16
 -         _6 = const true;                 // scope 2 at $DIR/unreachable.rs:+4:12: +4:16
--         switchInt(move _6) -> [false: bb4, otherwise: bb3]; // scope 2 at $DIR/unreachable.rs:+4:12: +4:16
+-         switchInt(move _6) -> [0: bb4, otherwise: bb3]; // scope 2 at $DIR/unreachable.rs:+4:12: +4:16
 +         unreachable;                     // scope 2 at $DIR/unreachable.rs:+4:12: +4:16
       }
   
index afd6b00aac3ea92ac3091c48a1168a46d031a151..fb778470e532323d8958c6dfc3001ec7b5a39bf3 100644 (file)
@@ -29,7 +29,7 @@
   
       bb1: {
           _3 = discriminant(_2);           // scope 2 at $DIR/unreachable_diverging.rs:+2:12: +2:22
-          switchInt(move _3) -> [1_isize: bb2, otherwise: bb6]; // scope 2 at $DIR/unreachable_diverging.rs:+2:12: +2:22
+          switchInt(move _3) -> [1: bb2, otherwise: bb6]; // scope 2 at $DIR/unreachable_diverging.rs:+2:12: +2:22
       }
   
       bb2: {
@@ -38,7 +38,7 @@
           StorageLive(_5);                 // scope 2 at $DIR/unreachable_diverging.rs:+3:9: +5:10
           StorageLive(_6);                 // scope 2 at $DIR/unreachable_diverging.rs:+3:12: +3:13
           _6 = _1;                         // scope 2 at $DIR/unreachable_diverging.rs:+3:12: +3:13
-          switchInt(move _6) -> [false: bb4, otherwise: bb3]; // scope 2 at $DIR/unreachable_diverging.rs:+3:12: +3:13
+          switchInt(move _6) -> [0: bb4, otherwise: bb3]; // scope 2 at $DIR/unreachable_diverging.rs:+3:12: +3:13
       }
   
       bb3: {
index eef7011149d3e5341cb26a448cab0e620bf4df92..984ef476e10209d4e5f830ccabc9f1af04a989ef 100644 (file)
           Deinit(_3);                      // scope 2 at $DIR/while_let_loops.rs:+2:28: +2:32
           discriminant(_3) = 0;            // scope 2 at $DIR/while_let_loops.rs:+2:28: +2:32
 -         _4 = discriminant(_3);           // scope 2 at $DIR/while_let_loops.rs:+2:15: +2:25
--         switchInt(move _4) -> [1_isize: bb1, otherwise: bb3]; // scope 2 at $DIR/while_let_loops.rs:+2:15: +2:25
+-         switchInt(move _4) -> [1: bb1, otherwise: bb3]; // scope 2 at $DIR/while_let_loops.rs:+2:15: +2:25
 +         _4 = const 0_isize;              // scope 2 at $DIR/while_let_loops.rs:+2:15: +2:25
-+         switchInt(const 0_isize) -> [1_isize: bb1, otherwise: bb3]; // scope 2 at $DIR/while_let_loops.rs:+2:15: +2:25
++         switchInt(const 0_isize) -> [1: bb1, otherwise: bb3]; // scope 2 at $DIR/while_let_loops.rs:+2:15: +2:25
       }
   
       bb1: {
-          switchInt(((_3 as Some).0: u32)) -> [0_u32: bb2, otherwise: bb3]; // scope 2 at $DIR/while_let_loops.rs:+2:15: +2:25
+          switchInt(((_3 as Some).0: u32)) -> [0: bb2, otherwise: bb3]; // scope 2 at $DIR/while_let_loops.rs:+2:15: +2:25
       }
   
       bb2: {
index 68aa3e5db32980b69defcf16cfc7ce80c11fbeb0..1556c240dc57a4335f848ca05289bff38cb366a6 100644 (file)
@@ -24,7 +24,7 @@ fn while_loop(_1: bool) -> () {
 
     bb2: {
         StorageDead(_3);                 // scope 0 at $DIR/while_storage.rs:+1:21: +1:22
-        switchInt(move _2) -> [false: bb7, otherwise: bb3]; // scope 0 at $DIR/while_storage.rs:+1:11: +1:22
+        switchInt(move _2) -> [0: bb7, otherwise: bb3]; // scope 0 at $DIR/while_storage.rs:+1:11: +1:22
     }
 
     bb3: {
@@ -39,7 +39,7 @@ fn while_loop(_1: bool) -> () {
 
     bb4: {
         StorageDead(_5);                 // scope 0 at $DIR/while_storage.rs:+2:22: +2:23
-        switchInt(move _4) -> [false: bb6, otherwise: bb5]; // scope 0 at $DIR/while_storage.rs:+2:12: +2:23
+        switchInt(move _4) -> [0: bb6, otherwise: bb5]; // scope 0 at $DIR/while_storage.rs:+2:12: +2:23
     }
 
     bb5: {
index 2c4309fbe66f96e8d0666620d8772120212692c7..3aa57d58908bb7b30d61a7eff9ffff9e7af95eff 100644 (file)
@@ -67,7 +67,7 @@ fn link(
             if crate_type != CrateType::Rlib {
                 sess.fatal(&format!("Crate type is {:?}", crate_type));
             }
-            let output_name = out_filename(sess, crate_type, &outputs, &*crate_name.as_str());
+            let output_name = out_filename(sess, crate_type, &outputs, crate_name);
             let mut out_file = ::std::fs::File::create(output_name).unwrap();
             write!(out_file, "This has been \"compiled\" successfully.").unwrap();
         }
index 436aebf1174ddb841086ae2699ecf5247b539315..d06cd9c6a54f077f1e115528565d17ab902fdb08 100644 (file)
@@ -80,7 +80,7 @@ ifdef RUSTC_BLESS_TEST
        rm -f expected_*
 endif
 
-include clear_expected_if_blessed
+-include clear_expected_if_blessed
 
 %: $(SOURCEDIR)/lib/%.rs
        # Compile the test library with coverage instrumentation
index 16d9a56e6bf78c472846074595c86a26aaede6b7..57497f5205384cc5883a6809b4c29feb75cfd921 100644 (file)
@@ -2,6 +2,7 @@ include ../../run-make-fulldeps/tools.mk
 
 # ignore-msvc
 # needs-rust-lld
+# ignore-s390x lld does not yet support s390x as target
 all:
        RUSTC_LOG=rustc_codegen_ssa::back::link=info $(RUSTC) -Z gcc-ld=lld -C link-args=-Wl,-v main.rs 2> $(TMPDIR)/output.txt
        $(CGREP) -e "^LLD [0-9]+\.[0-9]+\.[0-9]+" < $(TMPDIR)/output.txt
diff --git a/src/test/run-make/macos-deployment-target/Makefile b/src/test/run-make/macos-deployment-target/Makefile
new file mode 100644 (file)
index 0000000..70fca04
--- /dev/null
@@ -0,0 +1,21 @@
+# only-macos
+#
+# Check that a set deployment target actually makes it to the linker.
+# This is important since its a compatibility hazard. The linker will
+# generate load commands differently based on what minimum OS it can assume.
+
+include ../../run-make-fulldeps/tools.mk
+
+ifeq ($(strip $(shell uname -m)),arm64)
+       GREP_PATTERN = "minos 11.0"
+else
+       GREP_PATTERN = "version 10.9"
+endif
+
+OUT_FILE=$(TMPDIR)/with_deployment_target.dylib
+all:
+       env MACOSX_DEPLOYMENT_TARGET=10.9 $(RUSTC) with_deployment_target.rs -o $(OUT_FILE)
+# XXX: The check is for either the x86_64 minimum OR the aarch64 minimum (M1 starts at macOS 11).
+# They also use different load commands, so we let that change with each too. The aarch64 check
+# isn't as robust as the x86 one, but testing both seems unneeded.
+       vtool -show-build $(OUT_FILE) | $(CGREP) -e $(GREP_PATTERN)
diff --git a/src/test/run-make/macos-deployment-target/with_deployment_target.rs b/src/test/run-make/macos-deployment-target/with_deployment_target.rs
new file mode 100644 (file)
index 0000000..342fe0e
--- /dev/null
@@ -0,0 +1,4 @@
+#![crate_type = "cdylib"]
+
+#[allow(dead_code)]
+fn something_and_nothing() {}
diff --git a/src/test/rustdoc-gui/basic.goml b/src/test/rustdoc-gui/basic.goml
deleted file mode 100644 (file)
index 6029283..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-goto: "file://" + |DOC_PATH| + "/test_docs/index.html"
-assert: ("#functions")
-goto: "./struct.Foo.html"
-assert: ("div.item-decl")
index 4e316ce0bcbfd45b7cbda1a2c965b9be6d0e32fc..8645c1b1949e3f79533a5d76345bea8aec5285b6 100644 (file)
@@ -2,3 +2,50 @@ goto: "file://" + |DOC_PATH| + "/test_docs/doc_block_table/struct.DocBlockTable.
 
 compare-elements-css: (".impl-items .docblock table th", ".top-doc .docblock table th", ["border"])
 compare-elements-css: (".impl-items .docblock table td", ".top-doc .docblock table td", ["border"])
+
+define-function: (
+    "check-colors",
+    (theme, border_color, zebra_stripe_color),
+    [
+        ("local-storage", {"rustdoc-use-system-theme": "false", "rustdoc-theme": |theme|}),
+        ("reload"),
+        ("assert-css", (".top-doc .docblock table tbody tr:nth-child(1)", {
+            "background-color": "rgba(0, 0, 0, 0)",
+        })),
+        ("assert-css", (".top-doc .docblock table tbody tr:nth-child(2)", {
+            "background-color": |zebra_stripe_color|,
+        })),
+        ("assert-css", (".top-doc .docblock table tbody tr:nth-child(3)", {
+            "background-color": "rgba(0, 0, 0, 0)",
+        })),
+        ("assert-css", (".top-doc .docblock table tbody tr:nth-child(4)", {
+            "background-color": |zebra_stripe_color|,
+        })),
+        ("assert-css", (".top-doc .docblock table td", {
+            "border-style": "solid",
+            "border-width": "1px",
+            "border-color": |border_color|,
+        })),
+        ("assert-css", (".top-doc .docblock table th", {
+            "border-style": "solid",
+            "border-width": "1px",
+            "border-color": |border_color|,
+        })),
+    ]
+)
+
+call-function: ("check-colors", {
+    "theme": "dark",
+    "border_color": "rgb(224, 224, 224)",
+    "zebra_stripe_color": "rgb(42, 42, 42)",
+})
+call-function: ("check-colors", {
+    "theme": "ayu",
+    "border_color": "rgb(92, 103, 115)",
+    "zebra_stripe_color": "rgb(25, 31, 38)",
+})
+call-function: ("check-colors", {
+    "theme": "light",
+    "border_color": "rgb(224, 224, 224)",
+    "zebra_stripe_color": "rgb(245, 245, 245)",
+})
index 230abb236bd64aa1fba2215737c68bd63bc3b0e4..8dfc49285f2eb6695818d2d5a6090a3728ba3349 100644 (file)
@@ -3,3 +3,8 @@ goto: "file://" + |DOC_PATH| + "/test_docs/enum.WhoLetTheDogOut.html"
 
 assert-css: (".variants > .variant", {"margin": "0px 0px 12px"})
 assert-css: (".variants > .docblock", {"margin": "0px 0px 32px 24px"})
+
+assert-css: (
+    "details.non-exhaustive > summary",
+    {"font-family": '"Fira Sans", Arial, NanumBarunGothic, sans-serif'},
+)
index 397bcd40b36c4bbc4a28780e4cd2030a68d3a06b..ed36bcdec17d2261f9ad058f6b3a1724006fa910 100644 (file)
@@ -1,3 +1,4 @@
+// This test ensures that the margins on methods are coherent inside an impl block.
 goto: "file://" + |DOC_PATH| + "/test_docs/trait_members/struct.HasTrait.html#impl-TraitMembers-for-HasTrait"
 
 assert-count: ("#trait-implementations-list > .rustdoc-toggle", 1)
index 2a263a87a47566b834700fc8763af3db24e03cbb..bba518db099a49693956915158ffb3e224478716 100644 (file)
@@ -1,4 +1,19 @@
 goto: "file://" + |DOC_PATH| + "/scrape_examples/fn.test.html"
+
+// The next/prev buttons vertically scroll the code viewport between examples
+store-property: (initialScrollTop, ".scraped-example-list > .scraped-example pre", "scrollTop")
+focus: ".scraped-example-list > .scraped-example .next"
+press-key: "Enter"
+assert-property-false: (".scraped-example-list > .scraped-example pre", {
+       "scrollTop": |initialScrollTop|
+})
+focus: ".scraped-example-list > .scraped-example .prev"
+press-key: "Enter"
+assert-property: (".scraped-example-list > .scraped-example pre", {
+       "scrollTop": |initialScrollTop|
+})
+
+// The expand button increases the scrollHeight of the minimized code viewport
 store-property: (smallOffsetHeight, ".scraped-example-list > .scraped-example pre", "offsetHeight")
 assert-property-false: (".scraped-example-list > .scraped-example pre", {
        "scrollHeight": |smallOffsetHeight|
diff --git a/src/test/rustdoc-gui/scrape-examples-fonts.goml b/src/test/rustdoc-gui/scrape-examples-fonts.goml
new file mode 100644 (file)
index 0000000..b7d7f4c
--- /dev/null
@@ -0,0 +1,8 @@
+goto: "file://" + |DOC_PATH| + "/scrape_examples/fn.test_many.html"
+
+store-value: (font, '"Fira Sans", Arial, NanumBarunGothic, sans-serif')
+
+wait-for-css: (".scraped-example-title", {"font-family": |font|})
+wait-for-css: (".more-examples-toggle summary", {"font-family": |font|})
+wait-for-css: (".more-examples-toggle .hide-more", {"font-family": |font|})
+wait-for-css: (".example-links a", {"font-family": |font|})
diff --git a/src/test/rustdoc-gui/scrape-examples-toggle.goml b/src/test/rustdoc-gui/scrape-examples-toggle.goml
new file mode 100644 (file)
index 0000000..ee720af
--- /dev/null
@@ -0,0 +1,14 @@
+goto: "file://" + |DOC_PATH| + "/scrape_examples/fn.test_many.html"
+
+// Clicking "More examples..." will open additional examples
+assert-attribute-false: (".more-examples-toggle", {"open": ""})
+click: ".more-examples-toggle"
+assert-attribute: (".more-examples-toggle", {"open": ""})
+
+// Toggling all docs will close additional examples
+click: "#toggle-all-docs"
+assert-attribute-false: (".more-examples-toggle", {"open": ""})
+
+// After re-opening the docs, the additional examples should stay closed
+click: "#toggle-all-docs"
+assert-attribute-false: (".more-examples-toggle", {"open": ""})
diff --git a/src/test/rustdoc-gui/src/scrape_examples/examples/check-many-1.rs b/src/test/rustdoc-gui/src/scrape_examples/examples/check-many-1.rs
new file mode 100644 (file)
index 0000000..1d1bc50
--- /dev/null
@@ -0,0 +1,3 @@
+fn main() {
+    scrape_examples::test_many();
+}
diff --git a/src/test/rustdoc-gui/src/scrape_examples/examples/check-many-2.rs b/src/test/rustdoc-gui/src/scrape_examples/examples/check-many-2.rs
new file mode 100644 (file)
index 0000000..1d1bc50
--- /dev/null
@@ -0,0 +1,3 @@
+fn main() {
+    scrape_examples::test_many();
+}
diff --git a/src/test/rustdoc-gui/src/scrape_examples/examples/check-many-3.rs b/src/test/rustdoc-gui/src/scrape_examples/examples/check-many-3.rs
new file mode 100644 (file)
index 0000000..1d1bc50
--- /dev/null
@@ -0,0 +1,3 @@
+fn main() {
+    scrape_examples::test_many();
+}
diff --git a/src/test/rustdoc-gui/src/scrape_examples/examples/check-many-4.rs b/src/test/rustdoc-gui/src/scrape_examples/examples/check-many-4.rs
new file mode 100644 (file)
index 0000000..1d1bc50
--- /dev/null
@@ -0,0 +1,3 @@
+fn main() {
+    scrape_examples::test_many();
+}
diff --git a/src/test/rustdoc-gui/src/scrape_examples/examples/check-many-5.rs b/src/test/rustdoc-gui/src/scrape_examples/examples/check-many-5.rs
new file mode 100644 (file)
index 0000000..1d1bc50
--- /dev/null
@@ -0,0 +1,3 @@
+fn main() {
+    scrape_examples::test_many();
+}
diff --git a/src/test/rustdoc-gui/src/scrape_examples/examples/check-many-6.rs b/src/test/rustdoc-gui/src/scrape_examples/examples/check-many-6.rs
new file mode 100644 (file)
index 0000000..1d1bc50
--- /dev/null
@@ -0,0 +1,3 @@
+fn main() {
+    scrape_examples::test_many();
+}
diff --git a/src/test/rustdoc-gui/src/scrape_examples/examples/check-many-7.rs b/src/test/rustdoc-gui/src/scrape_examples/examples/check-many-7.rs
new file mode 100644 (file)
index 0000000..1d1bc50
--- /dev/null
@@ -0,0 +1,3 @@
+fn main() {
+    scrape_examples::test_many();
+}
index 3e69c6086ae2ed51928af3b47a919a8206fe3c8c..b3f682fe4973cd2ce83decbfe9c2b60d4812cb15 100644 (file)
@@ -22,4 +22,5 @@ fn main() {
         println!("hello world!");
         println!("hello world!");
     }
+    scrape_examples::test();
 }
index 6412de2c03afd2747786c62f9213945308b437b5..88b03cf26038dda6c123b642b14fe28da391c120 100644 (file)
@@ -5,3 +5,5 @@
 /// test();
 /// ```
 pub fn test() {}
+
+pub fn test_many() {}
index dea154c931935e95246ba1cb26e290fe45f83594..d6eeab803dfec3c7e9399be5f87f4cb3ba903b54 100644 (file)
@@ -76,6 +76,7 @@ fn as_ref(&self) -> &str {
 ///
 /// # title!
 #[doc(alias = "ThisIsAnAlias")]
+#[non_exhaustive]
 pub enum WhoLetTheDogOut {
     /// Woof!
     Woof,
@@ -342,6 +343,9 @@ pub trait DocBlockTableTrait {
     /// | header1                  | header2                  |
     /// |--------------------------|--------------------------|
     /// | Lorem Ipsum, Lorem Ipsum | Lorem Ipsum, Lorem Ipsum |
+    /// | Lorem Ipsum, Lorem Ipsum | Lorem Ipsum, Lorem Ipsum |
+    /// | Lorem Ipsum, Lorem Ipsum | Lorem Ipsum, Lorem Ipsum |
+    /// | Lorem Ipsum, Lorem Ipsum | Lorem Ipsum, Lorem Ipsum |
     pub struct DocBlockTable {}
 
     impl DocBlockTableTrait for DocBlockTable {
diff --git a/src/test/rustdoc-gui/stab-badge.goml b/src/test/rustdoc-gui/stab-badge.goml
new file mode 100644 (file)
index 0000000..aaed844
--- /dev/null
@@ -0,0 +1,41 @@
+// All stability badges should have rounded corners and colored backgrounds.
+goto: "file://" + |DOC_PATH| + "/test_docs/index.html"
+show-text: true
+define-function: (
+       "check-badge",
+       (theme, background, color),
+       [
+        ("local-storage", {"rustdoc-use-system-theme": "false", "rustdoc-theme": |theme|}),
+        ("goto", "file://" + |DOC_PATH| + "/test_docs/index.html"),
+               ("assert", (".docblock .stab")),
+               ("assert", (".item-table .stab")),
+               ("assert-css", (".stab", {
+                       "border-radius": "3px",
+                       "color": |color|,
+                       "background-color": |background|,
+               })),
+        ("goto", "file://" + |DOC_PATH| + "/test_docs/fn.replaced_function.html"),
+               ("assert", (".item-info .stab")),
+               ("assert-css", (".stab", {
+                       "border-radius": "3px",
+                       "color": |color|,
+                       "background-color": |background|,
+               })),
+       ]
+)
+
+call-function: ("check-badge", {
+       "theme": "ayu",
+       "color": "rgb(197, 197, 197)",
+       "background": "rgb(49, 69, 89)",
+})
+call-function: ("check-badge", {
+       "theme": "dark",
+       "color": "rgb(221, 221, 221)",
+       "background": "rgb(49, 69, 89)",
+})
+call-function: ("check-badge", {
+       "theme": "light",
+       "color": "rgb(0, 0, 0)",
+       "background": "rgb(255, 245, 214)",
+})
index 8c9fd0a8866d5ae042bff7b763c74cb039cbb5aa..45bb8daf1f20c575bc4bb0414e8c664b44a4b73b 100644 (file)
@@ -7,6 +7,10 @@ wait-for: 50
 // This is now collapsed so there shouldn't be the "open" attribute on details.
 assert-attribute-false: ("#main-content > details.top-doc", {"open": ""})
 assert-text: ("#toggle-all-docs", "[+]")
+assert-css: (
+    "#main-content > details.top-doc > summary",
+    {"font-family": '"Fira Sans", Arial, NanumBarunGothic, sans-serif'},
+)
 click: "#toggle-all-docs"
 // Not collapsed anymore so the "open" attribute should be back.
 wait-for-attribute: ("#main-content > details.top-doc", {"open": ""})
@@ -40,3 +44,32 @@ assert-attribute-false: (
 click: "#toggle-all-docs"
 wait-for-text: ("#toggle-all-docs", "[−]")
 assert-attribute: ("details.rustdoc-toggle", {"open": ""}, ALL)
+
+// Checking the toggles style.
+show-text: true
+define-function: (
+    "check-color",
+    (theme, filter),
+    [
+        // Setting the theme.
+       ("local-storage", {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"}),
+        // We reload the page so the local storage settings are being used.
+        ("reload"),
+
+        ("assert-css", ("details.rustdoc-toggle > summary::before", {
+            "opacity": "0.5",
+            "filter": |filter|,
+        }, ALL)),
+        ("move-cursor-to", "details.rustdoc-toggle summary"),
+        ("assert-css", ("details.rustdoc-toggle > summary:hover::before", {
+            "opacity": "1",
+            "filter": |filter|,
+        })),
+        // moving the cursor somewhere else to not mess with next function calls.
+        ("move-cursor-to", ".search-input"),
+    ]
+)
+
+call-function: ("check-color", {"theme": "ayu", "filter": "invert(1)"})
+call-function: ("check-color", {"theme": "dark", "filter": "invert(1)"})
+call-function: ("check-color", {"theme": "light", "filter": "none"})
diff --git a/src/test/rustdoc-json/intra-doc-links/auxiliary/enum_variant_in_trait_method.rs b/src/test/rustdoc-json/intra-doc-links/auxiliary/enum_variant_in_trait_method.rs
new file mode 100644 (file)
index 0000000..bfe85f5
--- /dev/null
@@ -0,0 +1,8 @@
+pub trait Trait {
+    /// [`Enum::Variant`]
+    fn method() {}
+}
+
+pub enum Enum {
+    Variant,
+}
diff --git a/src/test/rustdoc-json/intra-doc-links/foreign_variant.rs b/src/test/rustdoc-json/intra-doc-links/foreign_variant.rs
new file mode 100644 (file)
index 0000000..e296823
--- /dev/null
@@ -0,0 +1,13 @@
+// Regression test for <https://github.com/rust-lang/rust/issues/105025>
+// aux-build: enum_variant_in_trait_method.rs
+
+extern crate enum_variant_in_trait_method;
+
+pub struct Local;
+
+/// local impl
+impl enum_variant_in_trait_method::Trait for Local {}
+
+// @!has "$.index[*][?(@.name == 'Trait')]"
+// @!has "$.index[*][?(@.name == 'method')]"
+// @count "$.index[*][?(@.docs == 'local impl')].inner.items[*]" 0
diff --git a/src/test/rustdoc-json/reexport/auxiliary/trait_with_docs.rs b/src/test/rustdoc-json/reexport/auxiliary/trait_with_docs.rs
new file mode 100644 (file)
index 0000000..1e87966
--- /dev/null
@@ -0,0 +1,2 @@
+/// The Docs
+pub trait HasDocs {}
diff --git a/src/test/rustdoc-json/reexport/synthesize_trait_with_docs.rs b/src/test/rustdoc-json/reexport/synthesize_trait_with_docs.rs
new file mode 100644 (file)
index 0000000..25a7c08
--- /dev/null
@@ -0,0 +1,10 @@
+// Regression test for <https://github.com/rust-lang/rust/issues/105022>
+// aux-build: trait_with_docs.rs
+
+extern crate trait_with_docs;
+
+pub struct Local;
+
+impl trait_with_docs::HasDocs for Local {}
+
+// @!has "$.index[*][?(@.name == 'HasDocs')]"
index a4add43c6a1743fef3211fddf9b829162e43686b..55a51f739ab236c03c9e2ba0a6eb05835fa46d96 100644 (file)
@@ -1,12 +1,5 @@
 #![no_std]
 pub fn drop_default<T: core::default::Default>(_x: T) {}
 
-// FIXME(adotinthevoid): Theses shouldn't be here
-// @has "$.index[*][?(@.name=='Debug')]"
-
-// Debug may have several items. All we depend on here the that `fmt` is first. See
-// https://github.com/rust-lang/rust/pull/104525#issuecomment-1331087852 for why we
-// can't use [*].
-
-// @set Debug_fmt = "$.index[*][?(@.name=='Debug')].inner.items[0]"
-// @has "$.index[*][?(@.name=='fmt')].id" $Debug_fmt
+// @!has "$.index[*][?(@.name=='Debug')]"
+// @!has "$.index[*][?(@.name=='Default')]"
diff --git a/src/test/rustdoc-ui/const-evalutation-ice.rs b/src/test/rustdoc-ui/const-evalutation-ice.rs
new file mode 100644 (file)
index 0000000..0dd3bca
--- /dev/null
@@ -0,0 +1,11 @@
+// Just check we don't get an ICE for `N`.
+
+use std::cell::Cell;
+use std::mem;
+
+pub struct S {
+    s: Cell<usize>
+}
+
+pub const N: usize = 0 - (mem::size_of::<S>() != 400) as usize;
+//~^ ERROR evaluation of constant value failed
diff --git a/src/test/rustdoc-ui/const-evalutation-ice.stderr b/src/test/rustdoc-ui/const-evalutation-ice.stderr
new file mode 100644 (file)
index 0000000..5d9c16c
--- /dev/null
@@ -0,0 +1,9 @@
+error[E0080]: evaluation of constant value failed
+  --> $DIR/const-evalutation-ice.rs:10:22
+   |
+LL | pub const N: usize = 0 - (mem::size_of::<S>() != 400) as usize;
+   |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ attempt to compute `0_usize - 1_usize`, which would overflow
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0080`.
index b379f6febe29f1c8511aa49bcd902d650e7e37b3..14b7b17e04d3af476d66cc25a0c917976f8b0e53 100644 (file)
@@ -2,7 +2,7 @@ error: `cfg` predicate is not specified
   --> $DIR/doc-cfg.rs:3:7
    |
 LL | #[doc(cfg(), cfg(foo, bar))]
-   |       ^^^^^
+   |       ^^^^^ help: expected syntax is: `cfg(/* predicate */)`
 
 error: multiple `cfg` predicates are specified
   --> $DIR/doc-cfg.rs:3:23
@@ -14,7 +14,7 @@ error: `cfg` predicate is not specified
   --> $DIR/doc-cfg.rs:7:7
    |
 LL | #[doc(cfg())]
-   |       ^^^^^
+   |       ^^^^^ help: expected syntax is: `cfg(/* predicate */)`
 
 error: multiple `cfg` predicates are specified
   --> $DIR/doc-cfg.rs:8:16
index a19e452b459e19c85d84fb048b34a3b03cac84fc..1678352436315d74046949c81b8f3402974a7db3 100644 (file)
@@ -5,11 +5,9 @@ check_doc_test_visibility - run various visibility-related lints on doctests
   strip-priv-imports - strips all private import statements (`use`, `extern crate`) from a crate
    propagate-doc-cfg - propagates `#[doc(cfg(...))]` to child items
 collect-intra-doc-links - resolves intra-doc links
-check-code-block-syntax - validates syntax inside Rust code blocks
  collect-trait-impls - retrieves trait impls for items in the crate
 calculate-doc-coverage - counts the number of items with and without documentation
-check-invalid-html-tags - detects invalid HTML tags in doc comments
-     check-bare-urls - detects URLs that are not hyperlinks
+           run-lints - runs some of rustdoc's lints
 
 Default passes for rustdoc:
  collect-trait-impls
@@ -18,10 +16,8 @@ check_doc_test_visibility
        strip-private  (when not --document-private-items)
   strip-priv-imports  (when --document-private-items)
 collect-intra-doc-links
-check-code-block-syntax
-check-invalid-html-tags
    propagate-doc-cfg
-     check-bare-urls
+           run-lints
 
 Passes run with `--show-coverage`:
         strip-hidden  (when not --document-hidden-items)
diff --git a/src/test/rustdoc-ui/unable-fulfill-trait.rs b/src/test/rustdoc-ui/unable-fulfill-trait.rs
new file mode 100644 (file)
index 0000000..7035708
--- /dev/null
@@ -0,0 +1,13 @@
+// This test ensures that it's not crashing rustdoc.
+
+pub struct Foo<'a, 'b, T> {
+    field1: dyn Bar<'a, 'b,>,
+    //~^ ERROR
+    //~^^ ERROR
+}
+
+pub trait Bar<'x, 's, U>
+    where U: 'x,
+    Self:'x,
+    Self:'s
+{}
diff --git a/src/test/rustdoc-ui/unable-fulfill-trait.stderr b/src/test/rustdoc-ui/unable-fulfill-trait.stderr
new file mode 100644 (file)
index 0000000..a16b5b6
--- /dev/null
@@ -0,0 +1,26 @@
+error[E0107]: this trait takes 1 generic argument but 0 generic arguments were supplied
+  --> $DIR/unable-fulfill-trait.rs:4:17
+   |
+LL |     field1: dyn Bar<'a, 'b,>,
+   |                 ^^^ expected 1 generic argument
+   |
+note: trait defined here, with 1 generic parameter: `U`
+  --> $DIR/unable-fulfill-trait.rs:9:11
+   |
+LL | pub trait Bar<'x, 's, U>
+   |           ^^^         -
+help: add missing generic argument
+   |
+LL |     field1: dyn Bar<'a, 'b, U,>,
+   |                           +++
+
+error[E0227]: ambiguous lifetime bound, explicit lifetime bound required
+  --> $DIR/unable-fulfill-trait.rs:4:13
+   |
+LL |     field1: dyn Bar<'a, 'b,>,
+   |             ^^^^^^^^^^^^^^^^
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0107, E0227.
+For more information about an error, try `rustc --explain E0107`.
index 22e37821322885138e2964336c92e90c5c588d1a..94cf7b94241df8d79144969b852f538de8ccfa88 100644 (file)
@@ -77,6 +77,7 @@
     -Z                         location-detail=val -- what location details should be tracked when using caller_location, either `none`, or a comma separated list of location details, for which valid options are `file`, `line`, and `column` (default: `file,line,column`)
     -Z                                      ls=val -- list the symbols defined by a library crate (default: no)
     -Z                         macro-backtrace=val -- show macro backtraces (default: no)
+    -Z             maximal-hir-to-mir-coverage=val -- save as much information as possible about the correspondence between MIR and HIR as source scopes (default: no)
     -Z                         merge-functions=val -- control the operation of the MergeFunctions LLVM pass, taking the same values as the target option of the same name
     -Z                              meta-stats=val -- gather metadata statistics (default: no)
     -Z                          mir-emit-retag=val -- emit Retagging MIR statements, interpreted e.g., by miri; implies -Zmir-opt-level=0 (default: no)
@@ -90,7 +91,6 @@
     -Z                             no-analysis=val -- parse and expand the source, but run no analysis
     -Z                              no-codegen=val -- run all passes except codegen; no output
     -Z              no-generate-arange-section=val -- omit DWARF address ranges that give faster lookups
-    -Z                     no-interleave-lints=val -- execute lints separately; allows benchmarking individual lints
     -Z                           no-leak-check=val -- disable the 'leak check' for subtyping; unsound, but useful for tests
     -Z                                 no-link=val -- compile without linking
     -Z                        no-parallel-llvm=val -- run LLVM in non-parallel mode (while keeping codegen-units and ThinLTO)
diff --git a/src/test/rustdoc/bounds-in-multiple-parts.rs b/src/test/rustdoc/bounds-in-multiple-parts.rs
new file mode 100644 (file)
index 0000000..279e3c1
--- /dev/null
@@ -0,0 +1,20 @@
+#![crate_name = "foo"]
+
+pub trait Eq {}
+pub trait Eq2 {}
+
+// Checking that "where predicates" and "generics params" are merged.
+// @has 'foo/trait.T.html'
+// @has - "//*[@id='tymethod.f']/h4" "fn f<'a, 'b, 'c, T>()where Self: Eq, T: Eq + 'a, 'c: 'b + 'a,"
+pub trait T {
+    fn f<'a, 'b, 'c: 'a, T: Eq + 'a>()
+        where Self: Eq, Self: Eq, T: Eq, 'c: 'b;
+}
+
+// Checking that a duplicated "where predicate" is removed.
+// @has 'foo/trait.T2.html'
+// @has - "//*[@id='tymethod.f']/h4" "fn f<T>()where Self: Eq + Eq2, T: Eq2 + Eq,"
+pub trait T2 {
+    fn f<T: Eq>()
+        where Self: Eq, Self: Eq2, T: Eq2;
+}
diff --git a/src/test/rustdoc/const-evalutation-ice.rs b/src/test/rustdoc/const-evalutation-ice.rs
deleted file mode 100644 (file)
index 68c7f9c..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-// Just check we don't get an ICE for `N`.
-
-use std::cell::Cell;
-use std::mem;
-
-pub struct S {
-    s: Cell<usize>
-}
-
-pub const N: usize = 0 - (mem::size_of::<S>() != 4) as usize;
index 7b931727e446d829c691a62b7e4142700989547e..90cbb77cb6b60a013b1b8475bfa9bdde21204227 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"]' \
-//     "impl<T: Clone> !AnAutoTrait for Foo<T>where T: Sync,"
+//     "impl<T> !AnAutoTrait for Foo<T>where T: Sync + Clone,"
 // @has impl_parts/trait.AnAutoTrait.html '//*[@id="implementors-list"]//h3[@class="code-header"]' \
-//     "impl<T: Clone> !AnAutoTrait for Foo<T>where T: Sync,"
+//     "impl<T> !AnAutoTrait for Foo<T>where T: Sync + Clone,"
 impl<T: Clone> !AnAutoTrait for Foo<T> where T: Sync {}
index 602ee1b1b1fcad577912f4a6c7bddb44305426b4..7ed9d6729b647a67523462e6ec57a04be926a407 100644 (file)
@@ -61,7 +61,7 @@ impl<T> S<T> {
     // @has - '//section[@id="method.foo"]/h4[@class="code-header"]/a[@class="trait"]' 'Clone'
     // @!has - '//section[@id="method.foo"]/h4[@class="code-header"]/span[@class="where"]' '~const'
     // @has - '//section[@id="method.foo"]/h4[@class="code-header"]/span[@class="where fmt-newline"]' ': Clone'
-    pub const fn foo<B: ~const Clone + ~const Destruct>()
+    pub const fn foo<B, C: ~const Clone + ~const Destruct>()
     where
         B: ~const Clone + ~const Destruct,
     {
index c74866f4a10b89afb03fa19838e394455d05f248..f7663e4616ae6784ca44d04afe6af378232d98ea 100644 (file)
@@ -1,4 +1,4 @@
-<div class="item-decl"><pre class="rust enum"><code>pub enum Cow&lt;'a, B:&#160;?<a class="trait" href="{{channel}}/core/marker/trait.Sized.html" title="trait core::marker::Sized">Sized</a> + 'a&gt;<span class="where fmt-newline">where<br />&#160;&#160;&#160;&#160;B: <a class="trait" href="trait.ToOwned.html" title="trait foo::ToOwned">ToOwned</a>&lt;dyn <a class="trait" href="{{channel}}/core/clone/trait.Clone.html" title="trait core::clone::Clone">Clone</a>&gt;,</span>{
+<div class="item-decl"><pre class="rust enum"><code>pub enum Cow&lt;'a, B&gt;<span class="where fmt-newline">where<br />&#160;&#160;&#160;&#160;B: <a class="trait" href="trait.ToOwned.html" title="trait foo::ToOwned">ToOwned</a>&lt;dyn <a class="trait" href="{{channel}}/core/clone/trait.Clone.html" title="trait core::clone::Clone">Clone</a>&gt; + ?<a class="trait" href="{{channel}}/core/marker/trait.Sized.html" title="trait core::marker::Sized">Sized</a> + 'a,</span>{
     Borrowed(<a class="primitive" href="{{channel}}/std/primitive.reference.html">&amp;'a </a>B),
     Whatever(<a class="primitive" href="{{channel}}/std/primitive.u32.html">u32</a>),
 }</code></pre></div>
\ No newline at end of file
index 1ba1367d20f72f1f5341d01a9a284807aac50968..fa3f224e7ad0f5d21deb3fc66599eb2bd162d3d5 100644 (file)
@@ -1,4 +1,4 @@
-<div class="item-decl"><pre class="rust struct"><code>pub struct Struct&lt;'a, B:&#160;?<a class="trait" href="{{channel}}/core/marker/trait.Sized.html" title="trait core::marker::Sized">Sized</a> + 'a&gt;<span class="where fmt-newline">where<br />&#160;&#160;&#160;&#160;B: <a class="trait" href="trait.ToOwned.html" title="trait foo::ToOwned">ToOwned</a>&lt;dyn <a class="trait" href="{{channel}}/core/clone/trait.Clone.html" title="trait core::clone::Clone">Clone</a>&gt;,</span>{
+<div class="item-decl"><pre class="rust struct"><code>pub struct Struct&lt;'a, B&gt;<span class="where fmt-newline">where<br />&#160;&#160;&#160;&#160;B: <a class="trait" href="trait.ToOwned.html" title="trait foo::ToOwned">ToOwned</a>&lt;dyn <a class="trait" href="{{channel}}/core/clone/trait.Clone.html" title="trait core::clone::Clone">Clone</a>&gt; + ?<a class="trait" href="{{channel}}/core/marker/trait.Sized.html" title="trait core::marker::Sized">Sized</a> + 'a,</span>{
     pub a: <a class="primitive" href="{{channel}}/std/primitive.reference.html">&amp;'a </a>B,
     pub b: <a class="primitive" href="{{channel}}/std/primitive.u32.html">u32</a>,
 }</code></pre></div>
\ No newline at end of file
index 0dfb6407d45f1f60ac0e7eb3593e2a2636f6dde2..7bb177debc3a8c828e6526c0f5a0e45ba47af870 100644 (file)
@@ -1,3 +1,3 @@
-<div class="item-decl"><pre class="rust union"><code>pub union Union&lt;'a, B:&#160;?<a class="trait" href="{{channel}}/core/marker/trait.Sized.html" title="trait core::marker::Sized">Sized</a> + 'a&gt;<span class="where fmt-newline">where<br />&#160;&#160;&#160;&#160;B: <a class="trait" href="trait.ToOwned.html" title="trait foo::ToOwned">ToOwned</a>&lt;dyn <a class="trait" href="{{channel}}/core/clone/trait.Clone.html" title="trait core::clone::Clone">Clone</a>&gt;,</span>{
+<div class="item-decl"><pre class="rust union"><code>pub union Union&lt;'a, B&gt;<span class="where fmt-newline">where<br />&#160;&#160;&#160;&#160;B: <a class="trait" href="trait.ToOwned.html" title="trait foo::ToOwned">ToOwned</a>&lt;dyn <a class="trait" href="{{channel}}/core/clone/trait.Clone.html" title="trait core::clone::Clone">Clone</a>&gt; + ?<a class="trait" href="{{channel}}/core/marker/trait.Sized.html" title="trait core::marker::Sized">Sized</a> + 'a,</span>{
     /* private fields */
 }</code></pre></div>
\ No newline at end of file
index 981631494fafdaf8a246a98b7e65a71335906b81..82679c9e10a100b0ec5241092ed43abc2f8ed7c4 100644 (file)
@@ -1,11 +1,3 @@
-warning: use of deprecated attribute `plugin`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/pull/64675
-  --> <crate attribute>:1:1
-   |
-LL | plugin(lint_plugin_test)
-   | ^^^^^^^^^^^^^^^^^^^^^^^^ help: may be removed in a future compiler version
-   |
-   = note: `#[warn(deprecated)]` on by default
-
 warning: item is named 'lintme'
   --> $DIR/lint-plugin-cmdline-load.rs:8:1
    |
@@ -14,5 +6,13 @@ LL | fn lintme() { }
    |
    = note: `#[warn(test_lint)]` on by default
 
+warning: use of deprecated attribute `plugin`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/pull/64675
+  --> <crate attribute>:1:1
+   |
+LL | plugin(lint_plugin_test)
+   | ^^^^^^^^^^^^^^^^^^^^^^^^ help: may be removed in a future compiler version
+   |
+   = note: `#[warn(deprecated)]` on by default
+
 warning: 2 warnings emitted
 
index b9774c044623cd9798c5172b8364c7b444436317..5e8891bf1f1ac224eb860bf78abf98263a39f2a3 100644 (file)
@@ -1,11 +1,3 @@
-warning: use of deprecated attribute `plugin`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/pull/64675
-  --> $DIR/lint-plugin-deny-attr.rs:5:1
-   |
-LL | #![plugin(lint_plugin_test)]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: may be removed in a future compiler version
-   |
-   = note: `#[warn(deprecated)]` on by default
-
 error: item is named 'lintme'
   --> $DIR/lint-plugin-deny-attr.rs:9:1
    |
@@ -18,5 +10,13 @@ note: the lint level is defined here
 LL | #![deny(test_lint)]
    |         ^^^^^^^^^
 
+warning: use of deprecated attribute `plugin`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/pull/64675
+  --> $DIR/lint-plugin-deny-attr.rs:5:1
+   |
+LL | #![plugin(lint_plugin_test)]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: may be removed in a future compiler version
+   |
+   = note: `#[warn(deprecated)]` on by default
+
 error: aborting due to previous error; 1 warning emitted
 
index cbabb09f6a5967cb26bacdc109895dc65c2669d5..d5d6b5352145c531ac081fc9e38279117c55bc1a 100644 (file)
@@ -1,11 +1,3 @@
-warning: use of deprecated attribute `plugin`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/pull/64675
-  --> $DIR/lint-plugin-deny-cmdline.rs:6:1
-   |
-LL | #![plugin(lint_plugin_test)]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: may be removed in a future compiler version
-   |
-   = note: `#[warn(deprecated)]` on by default
-
 error: item is named 'lintme'
   --> $DIR/lint-plugin-deny-cmdline.rs:9:1
    |
@@ -14,5 +6,13 @@ LL | fn lintme() { }
    |
    = note: requested on the command line with `-D test-lint`
 
+warning: use of deprecated attribute `plugin`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/pull/64675
+  --> $DIR/lint-plugin-deny-cmdline.rs:6:1
+   |
+LL | #![plugin(lint_plugin_test)]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: may be removed in a future compiler version
+   |
+   = note: `#[warn(deprecated)]` on by default
+
 error: aborting due to previous error; 1 warning emitted
 
index 4833f6971c17170b5eb30465469b4d3614c1731b..cf31b3ec1587e788d6a1c748c8ed2c55f1ce4d41 100644 (file)
@@ -11,7 +11,6 @@ fn lintme() {} //~ ERROR item is named 'lintme'
 #[allow(test_lint)]
 //~^ ERROR allow(test_lint) incompatible
 //~| ERROR allow(test_lint) incompatible
-//~| ERROR allow(test_lint) incompatible
 pub fn main() {
     lintme();
 }
index e11a4f844935266a03ee7a6d98652981b36e7903..ae34b25cc2f808002972340723ac46c7eda961db 100644 (file)
@@ -7,23 +7,6 @@ LL | #![forbid(test_lint)]
 LL | #[allow(test_lint)]
    |         ^^^^^^^^^ overruled by previous forbid
 
-error[E0453]: allow(test_lint) incompatible with previous forbid
-  --> $DIR/lint-plugin-forbid-attrs.rs:11:9
-   |
-LL | #![forbid(test_lint)]
-   |           --------- `forbid` level set here
-...
-LL | #[allow(test_lint)]
-   |         ^^^^^^^^^ overruled by previous forbid
-
-warning: use of deprecated attribute `plugin`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/pull/64675
-  --> $DIR/lint-plugin-forbid-attrs.rs:5:1
-   |
-LL | #![plugin(lint_plugin_test)]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: may be removed in a future compiler version
-   |
-   = note: `#[warn(deprecated)]` on by default
-
 error: item is named 'lintme'
   --> $DIR/lint-plugin-forbid-attrs.rs:9:1
    |
@@ -45,6 +28,14 @@ LL | #![forbid(test_lint)]
 LL | #[allow(test_lint)]
    |         ^^^^^^^^^ overruled by previous forbid
 
-error: aborting due to 4 previous errors; 1 warning emitted
+warning: use of deprecated attribute `plugin`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/pull/64675
+  --> $DIR/lint-plugin-forbid-attrs.rs:5:1
+   |
+LL | #![plugin(lint_plugin_test)]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: may be removed in a future compiler version
+   |
+   = note: `#[warn(deprecated)]` on by default
+
+error: aborting due to 3 previous errors; 1 warning emitted
 
 For more information about this error, try `rustc --explain E0453`.
index ce034ee38d70c115df122f6819a3c1d8d223f92d..b9d1aa85a69308694fae84a4baabb14c86518989 100644 (file)
@@ -9,7 +9,7 @@ fn lintme() { } //~ ERROR item is named 'lintme'
 
 #[allow(test_lint)] //~ ERROR allow(test_lint) incompatible
                     //~| ERROR allow(test_lint) incompatible
-                    //~| ERROR allow(test_lint)
+
 pub fn main() {
     lintme();
 }
index 09c19af617a2995b5ff6bd51f3f0fe5ac69d426d..491c4d2064681e9ae467a2f5b8a8399160cc253b 100644 (file)
@@ -6,22 +6,6 @@ LL | #[allow(test_lint)]
    |
    = note: `forbid` lint level was set on command line
 
-error[E0453]: allow(test_lint) incompatible with previous forbid
-  --> $DIR/lint-plugin-forbid-cmdline.rs:10:9
-   |
-LL | #[allow(test_lint)]
-   |         ^^^^^^^^^ overruled by previous forbid
-   |
-   = note: `forbid` lint level was set on command line
-
-warning: use of deprecated attribute `plugin`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/pull/64675
-  --> $DIR/lint-plugin-forbid-cmdline.rs:6:1
-   |
-LL | #![plugin(lint_plugin_test)]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: may be removed in a future compiler version
-   |
-   = note: `#[warn(deprecated)]` on by default
-
 error: item is named 'lintme'
   --> $DIR/lint-plugin-forbid-cmdline.rs:8:1
    |
@@ -38,6 +22,14 @@ LL | #[allow(test_lint)]
    |
    = note: `forbid` lint level was set on command line
 
-error: aborting due to 4 previous errors; 1 warning emitted
+warning: use of deprecated attribute `plugin`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/pull/64675
+  --> $DIR/lint-plugin-forbid-cmdline.rs:6:1
+   |
+LL | #![plugin(lint_plugin_test)]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: may be removed in a future compiler version
+   |
+   = note: `#[warn(deprecated)]` on by default
+
+error: aborting due to 3 previous errors; 1 warning emitted
 
 For more information about this error, try `rustc --explain E0453`.
index 765832071cbeaf43029bb3afa5f4e4a08945813c..dd5d3d72ecf39baff81953fceebedeec5c48deee 100644 (file)
@@ -1,11 +1,3 @@
-warning: use of deprecated attribute `plugin`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/pull/64675
-  --> $DIR/lint-plugin.rs:5:1
-   |
-LL | #![plugin(lint_plugin_test)]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: may be removed in a future compiler version
-   |
-   = note: `#[warn(deprecated)]` on by default
-
 warning: item is named 'lintme'
   --> $DIR/lint-plugin.rs:8:1
    |
@@ -14,5 +6,13 @@ LL | fn lintme() { }
    |
    = note: `#[warn(test_lint)]` on by default
 
+warning: use of deprecated attribute `plugin`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/pull/64675
+  --> $DIR/lint-plugin.rs:5:1
+   |
+LL | #![plugin(lint_plugin_test)]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: may be removed in a future compiler version
+   |
+   = note: `#[warn(deprecated)]` on by default
+
 warning: 2 warnings emitted
 
index b4fb9e22da417da4e37bf9ae855dd254a0a2de5d..b060e3a3e38b4c10eaac0a881b39258628a46961 100644 (file)
@@ -6,18 +6,6 @@ warning: lint name `test_lint` is deprecated and does not have an effect anymore
    |
    = note: requested on the command line with `-A test_lint`
 
-warning: use of deprecated attribute `plugin`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/pull/64675
-  --> $DIR/lint-tool-cmdline-allow.rs:7:1
-   |
-LL | #![plugin(lint_tool_test)]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: may be removed in a future compiler version
-   |
-   = note: `#[warn(deprecated)]` on by default
-
-warning: lint name `test_lint` is deprecated and does not have an effect anymore. Use: clippy::test_lint
-   |
-   = note: requested on the command line with `-A test_lint`
-
 warning: item is named 'lintme'
   --> $DIR/lint-tool-cmdline-allow.rs:9:1
    |
@@ -26,9 +14,17 @@ LL | fn lintme() {}
    |
    = note: `#[warn(clippy::test_lint)]` on by default
 
+warning: use of deprecated attribute `plugin`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/pull/64675
+  --> $DIR/lint-tool-cmdline-allow.rs:7:1
+   |
+LL | #![plugin(lint_tool_test)]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: may be removed in a future compiler version
+   |
+   = note: `#[warn(deprecated)]` on by default
+
 warning: lint name `test_lint` is deprecated and does not have an effect anymore. Use: clippy::test_lint
    |
    = note: requested on the command line with `-A test_lint`
 
-warning: 6 warnings emitted
+warning: 5 warnings emitted
 
index 0d04eb6fcfa968be6ad6f942561531619a719bda..f92bcd213b844a272914c36cf2ceea10bb58ab0f 100644 (file)
 //~^ WARNING lint name `test_lint` is deprecated and may not have an effect in the future
 //~| WARNING lint name `test_lint` is deprecated and may not have an effect in the future
 //~| WARNING lint name `test_lint` is deprecated and may not have an effect in the future
-//~| WARNING lint name `test_lint` is deprecated and may not have an effect in the future
 #![deny(clippy_group)]
 //~^ WARNING lint name `clippy_group` is deprecated and may not have an effect in the future
 //~| WARNING lint name `clippy_group` is deprecated and may not have an effect in the future
 //~| WARNING lint name `clippy_group` is deprecated and may not have an effect in the future
-//~| WARNING lint name `clippy_group` is deprecated and may not have an effect in the future
 
 fn lintme() { } //~ ERROR item is named 'lintme'
 
@@ -32,7 +30,6 @@ fn lintmetoo() { } //~ ERROR item is named 'lintmetoo'
 //~^ WARNING lint name `test_group` is deprecated and may not have an effect in the future
 //~| WARNING lint name `test_group` is deprecated and may not have an effect in the future
 //~| WARNING lint name `test_group` is deprecated and may not have an effect in the future
-//~| WARNING lint name `test_group` is deprecated and may not have an effect in the future
 #[deny(this_lint_does_not_exist)] //~ WARNING unknown lint: `this_lint_does_not_exist`
 fn hello() {
     fn lintmetoo() { }
index af9b8dedc73afaa6c82005016443327ad1d44621..027cf8f80cff28b2c1ed539c9b1230dabde0e9c0 100644 (file)
@@ -7,13 +7,13 @@ LL | #![cfg_attr(foo, warn(test_lint))]
    = note: `#[warn(renamed_and_removed_lints)]` on by default
 
 warning: lint name `clippy_group` is deprecated and may not have an effect in the future.
-  --> $DIR/lint-tool-test.rs:14:9
+  --> $DIR/lint-tool-test.rs:13:9
    |
 LL | #![deny(clippy_group)]
    |         ^^^^^^^^^^^^ help: change it to: `clippy::group`
 
 warning: lint name `test_group` is deprecated and may not have an effect in the future.
-  --> $DIR/lint-tool-test.rs:31:9
+  --> $DIR/lint-tool-test.rs:29:9
    |
 LL | #[allow(test_group)]
    |         ^^^^^^^^^^ help: change it to: `clippy::test_group`
@@ -25,60 +25,26 @@ LL | #![cfg_attr(foo, warn(test_lint))]
    |                       ^^^^^^^^^ help: change it to: `clippy::test_lint`
 
 warning: lint name `clippy_group` is deprecated and may not have an effect in the future.
-  --> $DIR/lint-tool-test.rs:14:9
-   |
-LL | #![deny(clippy_group)]
-   |         ^^^^^^^^^^^^ help: change it to: `clippy::group`
-
-warning: lint name `test_group` is deprecated and may not have an effect in the future.
-  --> $DIR/lint-tool-test.rs:31:9
-   |
-LL | #[allow(test_group)]
-   |         ^^^^^^^^^^ help: change it to: `clippy::test_group`
-
-warning: unknown lint: `this_lint_does_not_exist`
-  --> $DIR/lint-tool-test.rs:36:8
-   |
-LL | #[deny(this_lint_does_not_exist)]
-   |        ^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: `#[warn(unknown_lints)]` on by default
-
-warning: use of deprecated attribute `plugin`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/pull/64675
-  --> $DIR/lint-tool-test.rs:6:1
-   |
-LL | #![plugin(lint_tool_test)]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: may be removed in a future compiler version
-   |
-   = note: `#[warn(deprecated)]` on by default
-
-warning: lint name `test_lint` is deprecated and may not have an effect in the future.
-  --> $DIR/lint-tool-test.rs:9:23
-   |
-LL | #![cfg_attr(foo, warn(test_lint))]
-   |                       ^^^^^^^^^ help: change it to: `clippy::test_lint`
-
-warning: lint name `clippy_group` is deprecated and may not have an effect in the future.
-  --> $DIR/lint-tool-test.rs:14:9
+  --> $DIR/lint-tool-test.rs:13:9
    |
 LL | #![deny(clippy_group)]
    |         ^^^^^^^^^^^^ help: change it to: `clippy::group`
 
 error: item is named 'lintme'
-  --> $DIR/lint-tool-test.rs:20:1
+  --> $DIR/lint-tool-test.rs:18:1
    |
 LL | fn lintme() { }
    | ^^^^^^^^^^^^^^^
    |
 note: the lint level is defined here
-  --> $DIR/lint-tool-test.rs:14:9
+  --> $DIR/lint-tool-test.rs:13:9
    |
 LL | #![deny(clippy_group)]
    |         ^^^^^^^^^^^^
    = note: `#[deny(clippy::test_lint)]` implied by `#[deny(clippy::group)]`
 
 error: item is named 'lintmetoo'
-  --> $DIR/lint-tool-test.rs:28:5
+  --> $DIR/lint-tool-test.rs:26:5
    |
 LL |     fn lintmetoo() { }
    |     ^^^^^^^^^^^^^^^^^^
@@ -86,11 +52,27 @@ LL |     fn lintmetoo() { }
    = note: `#[deny(clippy::test_group)]` implied by `#[deny(clippy::group)]`
 
 warning: lint name `test_group` is deprecated and may not have an effect in the future.
-  --> $DIR/lint-tool-test.rs:31:9
+  --> $DIR/lint-tool-test.rs:29:9
    |
 LL | #[allow(test_group)]
    |         ^^^^^^^^^^ help: change it to: `clippy::test_group`
 
+warning: unknown lint: `this_lint_does_not_exist`
+  --> $DIR/lint-tool-test.rs:33:8
+   |
+LL | #[deny(this_lint_does_not_exist)]
+   |        ^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(unknown_lints)]` on by default
+
+warning: use of deprecated attribute `plugin`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/pull/64675
+  --> $DIR/lint-tool-test.rs:6:1
+   |
+LL | #![plugin(lint_tool_test)]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: may be removed in a future compiler version
+   |
+   = note: `#[warn(deprecated)]` on by default
+
 warning: lint name `test_lint` is deprecated and may not have an effect in the future.
   --> $DIR/lint-tool-test.rs:9:23
    |
@@ -98,16 +80,16 @@ LL | #![cfg_attr(foo, warn(test_lint))]
    |                       ^^^^^^^^^ help: change it to: `clippy::test_lint`
 
 warning: lint name `clippy_group` is deprecated and may not have an effect in the future.
-  --> $DIR/lint-tool-test.rs:14:9
+  --> $DIR/lint-tool-test.rs:13:9
    |
 LL | #![deny(clippy_group)]
    |         ^^^^^^^^^^^^ help: change it to: `clippy::group`
 
 warning: lint name `test_group` is deprecated and may not have an effect in the future.
-  --> $DIR/lint-tool-test.rs:31:9
+  --> $DIR/lint-tool-test.rs:29:9
    |
 LL | #[allow(test_group)]
    |         ^^^^^^^^^^ help: change it to: `clippy::test_group`
 
-error: aborting due to 2 previous errors; 14 warnings emitted
+error: aborting due to 2 previous errors; 11 warnings emitted
 
index d6dc179da7f9897b0112a5d23abb3f524bad9dc0..a93ba87470a9c045703a8d31a2d39b51884d04a5 100644 (file)
@@ -126,6 +126,7 @@ fn iter_exprs(depth: usize, f: &mut dyn FnMut(P<Expr>)) {
                         fn_decl: decl.clone(),
                         body: e,
                         fn_decl_span: DUMMY_SP,
+                        fn_arg_span: DUMMY_SP,
                     })))
                 });
             }
diff --git a/src/test/ui/associated-consts/issue-47814.rs b/src/test/ui/associated-consts/issue-47814.rs
new file mode 100644 (file)
index 0000000..a28b1c0
--- /dev/null
@@ -0,0 +1,14 @@
+struct ArpIPv4<'a> {
+    s: &'a u8
+}
+
+impl<'a> ArpIPv4<'a> {
+    const LENGTH: usize = 20;
+
+    pub fn to_buffer() -> [u8; Self::LENGTH] {
+        //~^ ERROR: generic `Self` types are currently not permitted in anonymous constants
+        unimplemented!()
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/associated-consts/issue-47814.stderr b/src/test/ui/associated-consts/issue-47814.stderr
new file mode 100644 (file)
index 0000000..2e4ddb8
--- /dev/null
@@ -0,0 +1,14 @@
+error: generic `Self` types are currently not permitted in anonymous constants
+  --> $DIR/issue-47814.rs:8:32
+   |
+LL |     pub fn to_buffer() -> [u8; Self::LENGTH] {
+   |                                ^^^^
+   |
+note: not a concrete type
+  --> $DIR/issue-47814.rs:5:10
+   |
+LL | impl<'a> ArpIPv4<'a> {
+   |          ^^^^^^^^^^^
+
+error: aborting due to previous error
+
index 5c7b065983e194f3af96f0c321e2355912882bf2..b2a437fcbfb85f242f06c8eb4478ecf6aa5b1a83 100644 (file)
@@ -1,9 +1,11 @@
+#![feature(type_ascription)]
+
 fn e() {
-    p:a<p:p<e=6>>
-    //~^ ERROR comparison operators
+    type_ascribe!(p, a<p:p<e=6>>);
+    //~^ ERROR cannot find type `a` in this scope
     //~| ERROR cannot find value
     //~| ERROR associated const equality
-    //~| ERROR associated const equality
+    //~| ERROR cannot find trait `p` in this scope
     //~| ERROR associated type bounds
 }
 
index 0406a16a39732fbd7b466aba15f5efd4e333f243..be0573a1301afb74cad09dda2c72e36dcba178e6 100644 (file)
@@ -1,65 +1,40 @@
-error: comparison operators cannot be chained
-  --> $DIR/issue-93835.rs:2:8
-   |
-LL | fn e() {
-   |        - while parsing this struct
-LL |     p:a<p:p<e=6>>
-   |        ^        ^
-   |
-   = help: use `::<...>` instead of `<...>` to specify lifetime, type, or const arguments
-   = help: or use `(...)` if you meant to specify fn arguments
-
 error[E0425]: cannot find value `p` in this scope
-  --> $DIR/issue-93835.rs:2:5
-   |
-LL |     p:a<p:p<e=6>>
-   |     ^ not found in this scope
-   |
-help: you might have meant to write a `struct` literal
-   |
-LL ~ fn e() { SomeStruct {
-LL |     p:a<p:p<e=6>>
- ...
-LL |
-LL ~ }}
+  --> $DIR/issue-93835.rs:4:19
    |
-help: maybe you meant to write a path separator here
-   |
-LL |     p::a<p:p<e=6>>
-   |      ~~
-help: maybe you meant to write an assignment here
-   |
-LL |     let p:a<p:p<e=6>>
-   |     ~~~~~
+LL |     type_ascribe!(p, a<p:p<e=6>>);
+   |                   ^ not found in this scope
 
-error[E0658]: associated const equality is incomplete
-  --> $DIR/issue-93835.rs:2:13
+error[E0412]: cannot find type `a` in this scope
+  --> $DIR/issue-93835.rs:4:22
    |
-LL |     p:a<p:p<e=6>>
-   |             ^^^
+LL |     type_ascribe!(p, a<p:p<e=6>>);
+   |                      ^ not found in this scope
+
+error[E0405]: cannot find trait `p` in this scope
+  --> $DIR/issue-93835.rs:4:26
    |
-   = note: see issue #92827 <https://github.com/rust-lang/rust/issues/92827> for more information
-   = help: add `#![feature(associated_const_equality)]` to the crate attributes to enable
+LL |     type_ascribe!(p, a<p:p<e=6>>);
+   |                          ^ not found in this scope
 
 error[E0658]: associated const equality is incomplete
-  --> $DIR/issue-93835.rs:2:13
+  --> $DIR/issue-93835.rs:4:28
    |
-LL |     p:a<p:p<e=6>>
-   |             ^^^
+LL |     type_ascribe!(p, a<p:p<e=6>>);
+   |                            ^^^
    |
    = note: see issue #92827 <https://github.com/rust-lang/rust/issues/92827> for more information
    = help: add `#![feature(associated_const_equality)]` to the crate attributes to enable
 
 error[E0658]: associated type bounds are unstable
-  --> $DIR/issue-93835.rs:2:9
+  --> $DIR/issue-93835.rs:4:24
    |
-LL |     p:a<p:p<e=6>>
-   |         ^^^^^^^^
+LL |     type_ascribe!(p, a<p:p<e=6>>);
+   |                        ^^^^^^^^
    |
    = note: see issue #52662 <https://github.com/rust-lang/rust/issues/52662> for more information
    = help: add `#![feature(associated_type_bounds)]` to the crate attributes to enable
 
 error: aborting due to 5 previous errors
 
-Some errors have detailed explanations: E0425, E0658.
-For more information about an error, try `rustc --explain E0425`.
+Some errors have detailed explanations: E0405, E0412, E0425, E0658.
+For more information about an error, try `rustc --explain E0405`.
diff --git a/src/test/ui/associated-inherent-types/issue-104260.rs b/src/test/ui/associated-inherent-types/issue-104260.rs
new file mode 100644 (file)
index 0000000..a73cd17
--- /dev/null
@@ -0,0 +1,14 @@
+// check-pass
+
+#![feature(inherent_associated_types)]
+#![allow(incomplete_features)]
+
+struct Foo;
+
+impl Foo {
+    type Bar<T> = u8;
+}
+
+fn main() {
+    let a: Foo::Bar<()>;
+}
diff --git a/src/test/ui/associated-inherent-types/normalize-projection-0.rs b/src/test/ui/associated-inherent-types/normalize-projection-0.rs
new file mode 100644 (file)
index 0000000..50763ec
--- /dev/null
@@ -0,0 +1,22 @@
+// check-pass
+
+#![feature(inherent_associated_types)]
+#![allow(incomplete_features)]
+
+struct S<T>(T);
+
+impl<T: O> S<T> {
+    type P = <T as O>::P;
+}
+
+trait O {
+    type P;
+}
+
+impl O for i32 {
+    type P = String;
+}
+
+fn main() {
+    let _: S<i32>::P = String::new();
+}
diff --git a/src/test/ui/associated-inherent-types/normalize-projection-1.rs b/src/test/ui/associated-inherent-types/normalize-projection-1.rs
new file mode 100644 (file)
index 0000000..2f7b255
--- /dev/null
@@ -0,0 +1,22 @@
+// check-pass
+
+#![feature(inherent_associated_types)]
+#![allow(incomplete_features)]
+
+struct S;
+
+impl S {
+    type P<T: O> = <T as O>::P;
+}
+
+trait O {
+    type P;
+}
+
+impl O for i32 {
+    type P = String;
+}
+
+fn main() {
+    let _: S::P<i32> = String::new();
+}
diff --git a/src/test/ui/associated-inherent-types/struct-generics.rs b/src/test/ui/associated-inherent-types/struct-generics.rs
new file mode 100644 (file)
index 0000000..8952b37
--- /dev/null
@@ -0,0 +1,15 @@
+// check-pass
+
+#![feature(inherent_associated_types)]
+#![allow(incomplete_features)]
+
+struct S<T>(T);
+
+impl<T> S<T> {
+    type P = T;
+}
+
+fn main() {
+    type A = S<()>::P;
+    let _: A = ();
+}
index 3be7f370da3f59cc176d6270805c719250085b9e..616623ee07759eeabd7c7fb4dc211d435aedd462 100644 (file)
@@ -40,7 +40,7 @@ LL |   async fn bar2<T>(_: T) -> ! {
 LL | |     panic!()
 LL | | }
    | |_^
-   = note: required because it captures the following types: `ResumeTy`, `Option<bool>`, `impl Future<Output = !>`, `()`
+   = note: required because it captures the following types: `&mut Context<'_>`, `Option<bool>`, `impl Future<Output = !>`, `()`
 note: required because it's used within this `async fn` body
   --> $DIR/async-await-let-else.rs:21:32
    |
diff --git a/src/test/ui/async-await/drop-track-bad-field-in-fru.rs b/src/test/ui/async-await/drop-track-bad-field-in-fru.rs
new file mode 100644 (file)
index 0000000..28ad776
--- /dev/null
@@ -0,0 +1,10 @@
+// compile-flags: -Zdrop-tracking
+// edition: 2021
+
+fn main() {}
+
+async fn foo() {
+    None { value: (), ..Default::default() }.await;
+    //~^ ERROR `Option<_>` is not a future
+    //~| ERROR variant `Option<_>::None` has no field named `value`
+}
diff --git a/src/test/ui/async-await/drop-track-bad-field-in-fru.stderr b/src/test/ui/async-await/drop-track-bad-field-in-fru.stderr
new file mode 100644 (file)
index 0000000..819b64a
--- /dev/null
@@ -0,0 +1,23 @@
+error[E0559]: variant `Option<_>::None` has no field named `value`
+  --> $DIR/drop-track-bad-field-in-fru.rs:7:12
+   |
+LL |     None { value: (), ..Default::default() }.await;
+   |            ^^^^^ `Option<_>::None` does not have this field
+
+error[E0277]: `Option<_>` is not a future
+  --> $DIR/drop-track-bad-field-in-fru.rs:7:45
+   |
+LL |     None { value: (), ..Default::default() }.await;
+   |                                             ^^^^^^
+   |                                             |
+   |                                             `Option<_>` is not a future
+   |                                             help: remove the `.await`
+   |
+   = help: the trait `Future` is not implemented for `Option<_>`
+   = note: Option<_> must be a future or must implement `IntoFuture` to be awaited
+   = note: required for `Option<_>` to implement `IntoFuture`
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0277, E0559.
+For more information about an error, try `rustc --explain E0277`.
diff --git a/src/test/ui/async-await/generator-not-future.rs b/src/test/ui/async-await/generator-not-future.rs
new file mode 100644 (file)
index 0000000..37d7cfa
--- /dev/null
@@ -0,0 +1,45 @@
+// edition:2018
+#![feature(generators, generator_trait)]
+
+use std::future::Future;
+use std::ops::Generator;
+
+async fn async_fn() {}
+fn returns_async_block() -> impl Future<Output = ()> {
+    async {}
+}
+fn returns_generator() -> impl Generator<(), Yield = (), Return = ()> {
+    || {
+        let _: () = yield ();
+    }
+}
+
+fn takes_future(_f: impl Future<Output = ()>) {}
+fn takes_generator<ResumeTy>(_g: impl Generator<ResumeTy, Yield = (), Return = ()>) {}
+
+fn main() {
+    // okay:
+    takes_future(async_fn());
+    takes_future(returns_async_block());
+    takes_future(async {});
+    takes_generator(returns_generator());
+    takes_generator(|| {
+        let _: () = yield ();
+    });
+
+    // async futures are not generators:
+    takes_generator(async_fn());
+    //~^ ERROR the trait bound
+    takes_generator(returns_async_block());
+    //~^ ERROR the trait bound
+    takes_generator(async {});
+    //~^ ERROR the trait bound
+
+    // generators are not futures:
+    takes_future(returns_generator());
+    //~^ ERROR is not a future
+    takes_future(|ctx| {
+        //~^ ERROR is not a future
+        ctx = yield ();
+    });
+}
diff --git a/src/test/ui/async-await/generator-not-future.stderr b/src/test/ui/async-await/generator-not-future.stderr
new file mode 100644 (file)
index 0000000..1b81b46
--- /dev/null
@@ -0,0 +1,81 @@
+error[E0277]: the trait bound `impl Future<Output = ()>: Generator<_>` is not satisfied
+  --> $DIR/generator-not-future.rs:31:21
+   |
+LL |     takes_generator(async_fn());
+   |     --------------- ^^^^^^^^^^ the trait `Generator<_>` is not implemented for `impl Future<Output = ()>`
+   |     |
+   |     required by a bound introduced by this call
+   |
+note: required by a bound in `takes_generator`
+  --> $DIR/generator-not-future.rs:18:39
+   |
+LL | fn takes_generator<ResumeTy>(_g: impl Generator<ResumeTy, Yield = (), Return = ()>) {}
+   |                                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `takes_generator`
+
+error[E0277]: the trait bound `impl Future<Output = ()>: Generator<_>` is not satisfied
+  --> $DIR/generator-not-future.rs:33:21
+   |
+LL |     takes_generator(returns_async_block());
+   |     --------------- ^^^^^^^^^^^^^^^^^^^^^ the trait `Generator<_>` is not implemented for `impl Future<Output = ()>`
+   |     |
+   |     required by a bound introduced by this call
+   |
+note: required by a bound in `takes_generator`
+  --> $DIR/generator-not-future.rs:18:39
+   |
+LL | fn takes_generator<ResumeTy>(_g: impl Generator<ResumeTy, Yield = (), Return = ()>) {}
+   |                                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `takes_generator`
+
+error[E0277]: the trait bound `[async block@$DIR/generator-not-future.rs:35:21: 35:29]: Generator<_>` is not satisfied
+  --> $DIR/generator-not-future.rs:35:21
+   |
+LL |     takes_generator(async {});
+   |     --------------- ^^^^^^^^ the trait `Generator<_>` is not implemented for `[async block@$DIR/generator-not-future.rs:35:21: 35:29]`
+   |     |
+   |     required by a bound introduced by this call
+   |
+note: required by a bound in `takes_generator`
+  --> $DIR/generator-not-future.rs:18:39
+   |
+LL | fn takes_generator<ResumeTy>(_g: impl Generator<ResumeTy, Yield = (), Return = ()>) {}
+   |                                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `takes_generator`
+
+error[E0277]: `impl Generator<Yield = (), Return = ()>` is not a future
+  --> $DIR/generator-not-future.rs:39:18
+   |
+LL |     takes_future(returns_generator());
+   |     ------------ ^^^^^^^^^^^^^^^^^^^ `impl Generator<Yield = (), Return = ()>` is not a future
+   |     |
+   |     required by a bound introduced by this call
+   |
+   = help: the trait `Future` is not implemented for `impl Generator<Yield = (), Return = ()>`
+   = note: impl Generator<Yield = (), Return = ()> must be a future or must implement `IntoFuture` to be awaited
+note: required by a bound in `takes_future`
+  --> $DIR/generator-not-future.rs:17:26
+   |
+LL | fn takes_future(_f: impl Future<Output = ()>) {}
+   |                          ^^^^^^^^^^^^^^^^^^^ required by this bound in `takes_future`
+
+error[E0277]: `[generator@$DIR/generator-not-future.rs:41:18: 41:23]` is not a future
+  --> $DIR/generator-not-future.rs:41:18
+   |
+LL |       takes_future(|ctx| {
+   |  _____------------_^
+   | |     |
+   | |     required by a bound introduced by this call
+LL | |
+LL | |         ctx = yield ();
+LL | |     });
+   | |_____^ `[generator@$DIR/generator-not-future.rs:41:18: 41:23]` is not a future
+   |
+   = help: the trait `Future` is not implemented for `[generator@$DIR/generator-not-future.rs:41:18: 41:23]`
+   = note: [generator@$DIR/generator-not-future.rs:41:18: 41:23] must be a future or must implement `IntoFuture` to be awaited
+note: required by a bound in `takes_future`
+  --> $DIR/generator-not-future.rs:17:26
+   |
+LL | fn takes_future(_f: impl Future<Output = ()>) {}
+   |                          ^^^^^^^^^^^^^^^^^^^ required by this bound in `takes_future`
+
+error: aborting due to 5 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
index 5c8d64fc6cb4c858810b1ea013dc2b3a2cb5f855..f1f0d7e5907d3277fb4d611d58674e0c8566969a 100644 (file)
@@ -4,11 +4,11 @@ error[E0311]: the parameter type `U` may not live long enough
 LL |     async fn foo(&self) -> &(T, U) where T: Debug + Sized, U: Hash;
    |                            ^^^^^^^
    |
-note: the parameter type `U` must be valid for the anonymous lifetime as defined here...
+note: the parameter type `U` must be valid for the anonymous lifetime defined here...
   --> $DIR/async-generics-and-bounds.rs:12:18
    |
 LL |     async fn foo(&self) -> &(T, U) where T: Debug + Sized, U: Hash;
-   |                  ^
+   |                  ^^^^^
 note: ...so that the reference type `&(T, U)` does not outlive the data it points at
   --> $DIR/async-generics-and-bounds.rs:12:28
    |
@@ -21,11 +21,11 @@ error[E0311]: the parameter type `T` may not live long enough
 LL |     async fn foo(&self) -> &(T, U) where T: Debug + Sized, U: Hash;
    |                            ^^^^^^^
    |
-note: the parameter type `T` must be valid for the anonymous lifetime as defined here...
+note: the parameter type `T` must be valid for the anonymous lifetime defined here...
   --> $DIR/async-generics-and-bounds.rs:12:18
    |
 LL |     async fn foo(&self) -> &(T, U) where T: Debug + Sized, U: Hash;
-   |                  ^
+   |                  ^^^^^
 note: ...so that the reference type `&(T, U)` does not outlive the data it points at
   --> $DIR/async-generics-and-bounds.rs:12:28
    |
index 6ae73d9e3a60175029633c5aac78ef88e8c281da..2f05564564cd2b383510547b3241c84cce117c43 100644 (file)
@@ -4,11 +4,11 @@ error[E0311]: the parameter type `U` may not live long enough
 LL |     async fn foo(&self) -> &(T, U);
    |                            ^^^^^^^
    |
-note: the parameter type `U` must be valid for the anonymous lifetime as defined here...
+note: the parameter type `U` must be valid for the anonymous lifetime defined here...
   --> $DIR/async-generics.rs:9:18
    |
 LL |     async fn foo(&self) -> &(T, U);
-   |                  ^
+   |                  ^^^^^
 note: ...so that the reference type `&(T, U)` does not outlive the data it points at
   --> $DIR/async-generics.rs:9:28
    |
@@ -21,11 +21,11 @@ error[E0311]: the parameter type `T` may not live long enough
 LL |     async fn foo(&self) -> &(T, U);
    |                            ^^^^^^^
    |
-note: the parameter type `T` must be valid for the anonymous lifetime as defined here...
+note: the parameter type `T` must be valid for the anonymous lifetime defined here...
   --> $DIR/async-generics.rs:9:18
    |
 LL |     async fn foo(&self) -> &(T, U);
-   |                  ^
+   |                  ^^^^^
 note: ...so that the reference type `&(T, U)` does not outlive the data it points at
   --> $DIR/async-generics.rs:9:28
    |
index 3f7448cecd157fa006043471198734e2d5c56184..d5481d277e40a5955a74d93de96c3b0a13816480 100644 (file)
@@ -1,5 +1,4 @@
-// check-fail
-// known-bug: #102682
+// check-pass
 // edition: 2021
 
 #![feature(async_fn_in_trait)]
diff --git a/src/test/ui/async-await/in-trait/async-lifetimes-and-bounds.stderr b/src/test/ui/async-await/in-trait/async-lifetimes-and-bounds.stderr
deleted file mode 100644 (file)
index 0f02420..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-error[E0309]: the parameter type `Self` may not live long enough
-  --> $DIR/async-lifetimes-and-bounds.rs:11:43
-   |
-LL |     async fn foo(&'a self, key: &'b T) -> (&'a Self, &'b T) where T: Debug + Sized;
-   |                                           ^^^^^^^^^^^^^^^^^
-   |
-   = help: consider adding an explicit lifetime bound `Self: 'a`...
-   = note: ...so that the reference type `&'a Self` does not outlive the data it points at
-
-error[E0309]: the parameter type `T` may not live long enough
-  --> $DIR/async-lifetimes-and-bounds.rs:11:43
-   |
-LL |     async fn foo(&'a self, key: &'b T) -> (&'a Self, &'b T) where T: Debug + Sized;
-   |                                           ^^^^^^^^^^^^^^^^^ ...so that the reference type `&'b T` does not outlive the data it points at
-   |
-help: consider adding an explicit lifetime bound...
-   |
-LL | trait MyTrait<'a, 'b, T: 'b> {
-   |                        ++++
-
-error: aborting due to 2 previous errors
-
-For more information about this error, try `rustc --explain E0309`.
index acbac471cf7e8638e0a989e531c4f63b6ef5f519..f298e45d2390b368dc7391a7b1989de9ab096f13 100644 (file)
@@ -1,5 +1,4 @@
-// check-fail
-// known-bug: #102682
+// check-pass
 // edition: 2021
 
 #![feature(async_fn_in_trait)]
diff --git a/src/test/ui/async-await/in-trait/async-lifetimes.stderr b/src/test/ui/async-await/in-trait/async-lifetimes.stderr
deleted file mode 100644 (file)
index 9a7d294..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-error[E0309]: the parameter type `Self` may not live long enough
-  --> $DIR/async-lifetimes.rs:9:43
-   |
-LL |     async fn foo(&'a self, key: &'b T) -> (&'a Self, &'b T);
-   |                                           ^^^^^^^^^^^^^^^^^
-   |
-   = help: consider adding an explicit lifetime bound `Self: 'a`...
-   = note: ...so that the reference type `&'a Self` does not outlive the data it points at
-
-error[E0309]: the parameter type `T` may not live long enough
-  --> $DIR/async-lifetimes.rs:9:43
-   |
-LL |     async fn foo(&'a self, key: &'b T) -> (&'a Self, &'b T);
-   |                                           ^^^^^^^^^^^^^^^^^ ...so that the reference type `&'b T` does not outlive the data it points at
-   |
-help: consider adding an explicit lifetime bound...
-   |
-LL | trait MyTrait<'a, 'b, T: 'b> {
-   |                        ++++
-
-error: aborting due to 2 previous errors
-
-For more information about this error, try `rustc --explain E0309`.
diff --git a/src/test/ui/async-await/in-trait/implied-bounds.rs b/src/test/ui/async-await/in-trait/implied-bounds.rs
new file mode 100644 (file)
index 0000000..52bceb3
--- /dev/null
@@ -0,0 +1,13 @@
+// check-pass
+// edition: 2021
+
+#![feature(async_fn_in_trait)]
+#![allow(incomplete_features)]
+
+trait TcpStack {
+    type Connection<'a>: Sized where Self: 'a;
+    fn connect<'a>(&'a self) -> Self::Connection<'a>;
+    async fn async_connect<'a>(&'a self) -> Self::Connection<'a>;
+}
+
+fn main() {}
diff --git a/src/test/ui/async-await/in-trait/lifetime-mismatch.rs b/src/test/ui/async-await/in-trait/lifetime-mismatch.rs
new file mode 100644 (file)
index 0000000..45ede19
--- /dev/null
@@ -0,0 +1,20 @@
+// edition:2021
+
+#![feature(async_fn_in_trait)]
+//~^ WARN the feature `async_fn_in_trait` is incomplete and may not be safe to use and/or cause compiler crashes
+
+trait MyTrait {
+    async fn foo<'a>(&self);
+    async fn bar(&self);
+}
+
+impl MyTrait for i32 {
+    async fn foo(&self) {}
+    //~^ ERROR lifetime parameters or bounds on method `foo` do not match the trait declaration
+
+    async fn bar(&self) {
+        self.foo();
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/async-await/in-trait/lifetime-mismatch.stderr b/src/test/ui/async-await/in-trait/lifetime-mismatch.stderr
new file mode 100644 (file)
index 0000000..d87adcc
--- /dev/null
@@ -0,0 +1,21 @@
+warning: the feature `async_fn_in_trait` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/lifetime-mismatch.rs:3:12
+   |
+LL | #![feature(async_fn_in_trait)]
+   |            ^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information
+   = note: `#[warn(incomplete_features)]` on by default
+
+error[E0195]: lifetime parameters or bounds on method `foo` do not match the trait declaration
+  --> $DIR/lifetime-mismatch.rs:12:17
+   |
+LL |     async fn foo<'a>(&self);
+   |                 ---- lifetimes in impl do not match this method in trait
+...
+LL |     async fn foo(&self) {}
+   |                 ^ lifetimes do not match method in trait
+
+error: aborting due to previous error; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0195`.
diff --git a/src/test/ui/async-await/in-trait/nested-rpit.rs b/src/test/ui/async-await/in-trait/nested-rpit.rs
new file mode 100644 (file)
index 0000000..ae8e0ae
--- /dev/null
@@ -0,0 +1,17 @@
+// check-pass
+// edition: 2021
+
+#![feature(async_fn_in_trait)]
+#![feature(return_position_impl_trait_in_trait)]
+#![allow(incomplete_features)]
+
+use std::future::Future;
+use std::marker::PhantomData;
+
+trait Lockable<K, V> {
+    async fn lock_all_entries(&self) -> impl Future<Output = Guard<'_>>;
+}
+
+struct Guard<'a>(PhantomData<&'a ()>);
+
+fn main() {}
diff --git a/src/test/ui/async-await/in-trait/return-type-suggestion.rs b/src/test/ui/async-await/in-trait/return-type-suggestion.rs
new file mode 100644 (file)
index 0000000..3446761
--- /dev/null
@@ -0,0 +1,14 @@
+// edition: 2021
+
+#![feature(async_fn_in_trait)]
+//~^ WARN the feature `async_fn_in_trait` is incomplete and may not be safe to use and/or cause compiler crashes
+
+trait A {
+    async fn e() {
+        Ok(())
+        //~^ ERROR mismatched types
+        //~| HELP consider using a semicolon here
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/async-await/in-trait/return-type-suggestion.stderr b/src/test/ui/async-await/in-trait/return-type-suggestion.stderr
new file mode 100644 (file)
index 0000000..5a9b15e
--- /dev/null
@@ -0,0 +1,23 @@
+warning: the feature `async_fn_in_trait` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/return-type-suggestion.rs:3:12
+   |
+LL | #![feature(async_fn_in_trait)]
+   |            ^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information
+   = note: `#[warn(incomplete_features)]` on by default
+
+error[E0308]: mismatched types
+  --> $DIR/return-type-suggestion.rs:8:9
+   |
+LL |         Ok(())
+   |         ^^^^^^- help: consider using a semicolon here: `;`
+   |         |
+   |         expected `()`, found enum `Result`
+   |
+   = note: expected unit type `()`
+                   found enum `Result<(), _>`
+
+error: aborting due to previous error; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0308`.
index f2802698fd5b646fdd3e993df175ae58705b5abe..1c90bedae790c66259bc6c47e956ebb90907e003 100644 (file)
@@ -57,7 +57,7 @@ note: required because it appears within the type `impl Future<Output = Arc<RefC
    |
 LL | fn make_non_send_future2() -> impl Future<Output = Arc<RefCell<i32>>> {
    |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   = note: required because it captures the following types: `ResumeTy`, `impl Future<Output = Arc<RefCell<i32>>>`, `()`, `Ready<i32>`
+   = note: required because it captures the following types: `&mut Context<'_>`, `impl Future<Output = Arc<RefCell<i32>>>`, `()`, `Ready<i32>`
 note: required because it's used within this `async` block
   --> $DIR/issue-68112.rs:60:20
    |
index 38eb85b302fd588abbeb8e8f4b82f84338fa21bb..e09ae7fedd8055f1f636f711bbe1fdd619048213 100644 (file)
@@ -57,7 +57,7 @@ note: required because it appears within the type `impl Future<Output = Arc<RefC
    |
 LL | fn make_non_send_future2() -> impl Future<Output = Arc<RefCell<i32>>> {
    |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   = note: required because it captures the following types: `ResumeTy`, `impl Future<Output = Arc<RefCell<i32>>>`, `()`, `i32`, `Ready<i32>`
+   = note: required because it captures the following types: `&mut Context<'_>`, `impl Future<Output = Arc<RefCell<i32>>>`, `()`, `i32`, `Ready<i32>`
 note: required because it's used within this `async` block
   --> $DIR/issue-68112.rs:60:20
    |
index 3d2b0402bc52c614564988f0e53b8705b0691acf..e6ad2f0d444bb7e8faa44cd6cc6f4a787fc87b80 100644 (file)
@@ -14,6 +14,9 @@ LL | |     });
    |
    = 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
+   = note: requirement occurs because of a mutable reference to `Context<'_>`
+   = note: mutable references are invariant over their type parameter
+   = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
 
 error: aborting due to previous error
 
index 721234aa4a782875a2e90e32d4c2f5bea168c7f0..a8fd97cde8f7a8bd7b9f64c71b96179ed7658dce 100644 (file)
@@ -18,7 +18,7 @@ LL |   async fn baz<T>(_c: impl FnMut() -> T) where T: Future<Output=()> {
    |  ___________________________________________________________________^
 LL | | }
    | |_^
-   = note: required because it captures the following types: `ResumeTy`, `impl Future<Output = ()>`, `()`
+   = note: required because it captures the following types: `&mut Context<'_>`, `impl Future<Output = ()>`, `()`
 note: required because it's used within this `async` block
   --> $DIR/issue-70935-complex-spans.rs:16:5
    |
index 17b4ef7bdc671705abd27ca37e8423cb94878cc2..25876d5084015f6720a31293c78bce0bb7c67a77 100644 (file)
@@ -11,7 +11,7 @@ LL | async fn foo() {
    |
    = help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `NotSend`
    = note: required because it appears within the type `(NotSend,)`
-   = note: required because it captures the following types: `ResumeTy`, `(NotSend,)`, `()`, `impl Future<Output = ()>`
+   = note: required because it captures the following types: `&mut Context<'_>`, `(NotSend,)`, `()`, `impl Future<Output = ()>`
 note: required because it's used within this `async fn` body
   --> $DIR/partial-drop-partial-reinit.rs:31:16
    |
index 34d8a159f1064bf05c1e448b9be5303830be108f..dba2a620779f0f446f537663fc8995a40037baaf 100644 (file)
@@ -11,7 +11,7 @@ LL | async fn foo() {
    |
    = help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `NotSend`
    = note: required because it appears within the type `(NotSend,)`
-   = note: required because it captures the following types: `ResumeTy`, `(NotSend,)`, `impl Future<Output = ()>`, `()`
+   = note: required because it captures the following types: `&mut Context<'_>`, `(NotSend,)`, `impl Future<Output = ()>`, `()`
 note: required because it's used within this `async fn` body
   --> $DIR/partial-drop-partial-reinit.rs:31:16
    |
diff --git a/src/test/ui/async-await/track-caller/issue-105134.rs b/src/test/ui/async-await/track-caller/issue-105134.rs
new file mode 100644 (file)
index 0000000..4e52b8e
--- /dev/null
@@ -0,0 +1,11 @@
+// check-pass
+// edition:2021
+
+#[track_caller]
+fn f() {
+    let _ = async {};
+}
+
+fn main() {
+    f();
+}
index b113c56412ff65322dc4646a9dd8593e4a863462..5ebfeb3f36ac162f402dc3b780f6767c2911d35a 100644 (file)
@@ -54,6 +54,19 @@ async fn foo_track_caller() {
     bar_track_caller().await
 }
 
+struct Foo;
+
+impl Foo {
+    #[track_caller]
+    async fn bar_assoc() {
+        panic!();
+    }
+}
+
+async fn foo_assoc() {
+    Foo::bar_assoc().await
+}
+
 fn panicked_at(f: impl FnOnce() + panic::UnwindSafe) -> u32 {
     let loc = Arc::new(Mutex::new(None));
 
@@ -73,4 +86,5 @@ fn panicked_at(f: impl FnOnce() + panic::UnwindSafe) -> u32 {
 fn main() {
     assert_eq!(panicked_at(|| block_on(foo())), 41);
     assert_eq!(panicked_at(|| block_on(foo_track_caller())), 54);
+    assert_eq!(panicked_at(|| block_on(foo_assoc())), 67);
 }
diff --git a/src/test/ui/attributes/unused-item-in-attr.rs b/src/test/ui/attributes/unused-item-in-attr.rs
new file mode 100644 (file)
index 0000000..70dcd54
--- /dev/null
@@ -0,0 +1,6 @@
+#[w = { extern crate alloc; }]
+//~^ ERROR unexpected expression: `{
+//~| ERROR cannot find attribute `w` in this scope
+fn f() {}
+
+fn main() {}
diff --git a/src/test/ui/attributes/unused-item-in-attr.stderr b/src/test/ui/attributes/unused-item-in-attr.stderr
new file mode 100644 (file)
index 0000000..92a8f58
--- /dev/null
@@ -0,0 +1,16 @@
+error: unexpected expression: `{
+           extern crate alloc;
+       }`
+  --> $DIR/unused-item-in-attr.rs:1:7
+   |
+LL | #[w = { extern crate alloc; }]
+   |       ^^^^^^^^^^^^^^^^^^^^^^^
+
+error: cannot find attribute `w` in this scope
+  --> $DIR/unused-item-in-attr.rs:1:3
+   |
+LL | #[w = { extern crate alloc; }]
+   |   ^
+
+error: aborting due to 2 previous errors
+
diff --git a/src/test/ui/auto-traits/bad-generics-on-dyn.rs b/src/test/ui/auto-traits/bad-generics-on-dyn.rs
new file mode 100644 (file)
index 0000000..3f8ac14
--- /dev/null
@@ -0,0 +1,11 @@
+#![feature(auto_traits)]
+
+auto trait Trait1<'a> {}
+//~^ ERROR auto traits cannot have generic parameters
+
+fn f<'a>(x: &dyn Trait1<'a>)
+{}
+
+fn main() {
+    f(&1);
+}
diff --git a/src/test/ui/auto-traits/bad-generics-on-dyn.stderr b/src/test/ui/auto-traits/bad-generics-on-dyn.stderr
new file mode 100644 (file)
index 0000000..ade69ce
--- /dev/null
@@ -0,0 +1,11 @@
+error[E0567]: auto traits cannot have generic parameters
+  --> $DIR/bad-generics-on-dyn.rs:3:18
+   |
+LL | auto trait Trait1<'a> {}
+   |            ------^^^^ help: remove the parameters
+   |            |
+   |            auto trait cannot have generic parameters
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0567`.
index 21c490965b14740a4e3b5cd08bc093ca7fc37b98..c986bc3fd1e3e15003216d93ffe183e8eb38f271 100644 (file)
@@ -6,15 +6,10 @@ LL |     x * y
    |
    = help: the trait `Mul<f32>` is not implemented for `i32`
    = help: the following other types implement trait `Mul<Rhs>`:
-             <&'a f32 as Mul<f32>>
-             <&'a f64 as Mul<f64>>
-             <&'a i128 as Mul<i128>>
-             <&'a i16 as Mul<i16>>
              <&'a i32 as Mul<i32>>
-             <&'a i64 as Mul<i64>>
-             <&'a i8 as Mul<i8>>
-             <&'a isize as Mul<isize>>
-           and 49 others
+             <&i32 as Mul<&i32>>
+             <i32 as Mul<&i32>>
+             <i32 as Mul>
 
 error: aborting due to previous error
 
index a4d5f212188d6bb978734f4a8d5b3de0fa3771ec..1b03bc3af9c72d8c4fbbc0d84141233aedf7b078 100644 (file)
@@ -1,15 +1,19 @@
 error[E0080]: evaluation of constant value failed
   --> $DIR/issue-81899.rs:11:5
    |
-LL | const _CONST: &[u8] = &f(&[], |_| {});
-   |                        -------------- inside `_CONST` at $DIR/issue-81899.rs:4:24
-...
+LL |     panic!()
+   |     ^^^^^^^^ the evaluated program panicked at 'explicit panic', $DIR/issue-81899.rs:11:5
+   |
+note: inside `f::<[closure@$DIR/issue-81899.rs:4:31: 4:34]>`
+  --> $DIR/issue-81899.rs:11:5
+   |
 LL |     panic!()
    |     ^^^^^^^^
-   |     |
-   |     the evaluated program panicked at 'explicit panic', $DIR/issue-81899.rs:11:5
-   |     inside `f::<[closure@$DIR/issue-81899.rs:4:31: 4:34]>` at $SRC_DIR/std/src/panic.rs:LL:COL
+note: inside `_CONST`
+  --> $DIR/issue-81899.rs:4:24
    |
+LL | const _CONST: &[u8] = &f(&[], |_| {});
+   |                        ^^^^^^^^^^^^^^
    = note: this error originates in the macro `$crate::panic::panic_2015` which comes from the expansion of the macro `panic` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 note: erroneous constant used
index b95ddc49c9964da69cab2d90c0c83124a1fe5f14..a5a571c6d4df09036758caf0ffe792cba65a8e02 100644 (file)
@@ -1,15 +1,19 @@
 error[E0080]: evaluation of constant value failed
   --> $DIR/issue-88434-minimal-example.rs:10:5
    |
-LL | const _CONST: &() = &f(&|_| {});
-   |                      ---------- inside `_CONST` at $DIR/issue-88434-minimal-example.rs:3:22
-...
+LL |     panic!()
+   |     ^^^^^^^^ the evaluated program panicked at 'explicit panic', $DIR/issue-88434-minimal-example.rs:10:5
+   |
+note: inside `f::<[closure@$DIR/issue-88434-minimal-example.rs:3:25: 3:28]>`
+  --> $DIR/issue-88434-minimal-example.rs:10:5
+   |
 LL |     panic!()
    |     ^^^^^^^^
-   |     |
-   |     the evaluated program panicked at 'explicit panic', $DIR/issue-88434-minimal-example.rs:10:5
-   |     inside `f::<[closure@$DIR/issue-88434-minimal-example.rs:3:25: 3:28]>` at $SRC_DIR/std/src/panic.rs:LL:COL
+note: inside `_CONST`
+  --> $DIR/issue-88434-minimal-example.rs:3:22
    |
+LL | const _CONST: &() = &f(&|_| {});
+   |                      ^^^^^^^^^^
    = note: this error originates in the macro `$crate::panic::panic_2015` which comes from the expansion of the macro `panic` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 note: erroneous constant used
index 604a6577639f458ff1db6ee86baf34b17e2a584e..00023c459a8e7228b6e5c4bcd3250debddb2c507 100644 (file)
@@ -1,15 +1,19 @@
 error[E0080]: evaluation of constant value failed
   --> $DIR/issue-88434-removal-index-should-be-less.rs:10:5
    |
-LL | const _CONST: &[u8] = &f(&[], |_| {});
-   |                        -------------- inside `_CONST` at $DIR/issue-88434-removal-index-should-be-less.rs:3:24
-...
+LL |     panic!()
+   |     ^^^^^^^^ the evaluated program panicked at 'explicit panic', $DIR/issue-88434-removal-index-should-be-less.rs:10:5
+   |
+note: inside `f::<[closure@$DIR/issue-88434-removal-index-should-be-less.rs:3:31: 3:34]>`
+  --> $DIR/issue-88434-removal-index-should-be-less.rs:10:5
+   |
 LL |     panic!()
    |     ^^^^^^^^
-   |     |
-   |     the evaluated program panicked at 'explicit panic', $DIR/issue-88434-removal-index-should-be-less.rs:10:5
-   |     inside `f::<[closure@$DIR/issue-88434-removal-index-should-be-less.rs:3:31: 3:34]>` at $SRC_DIR/std/src/panic.rs:LL:COL
+note: inside `_CONST`
+  --> $DIR/issue-88434-removal-index-should-be-less.rs:3:24
    |
+LL | const _CONST: &[u8] = &f(&[], |_| {});
+   |                        ^^^^^^^^^^^^^^
    = note: this error originates in the macro `$crate::panic::panic_2015` which comes from the expansion of the macro `panic` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 note: erroneous constant used
index b07425bd82501fff334063b0f1d6eb6433ff37ac..d4fc723fa8176c07eabcedbf0a8aaf54d9c4d98f 100644 (file)
@@ -19,7 +19,7 @@ note: required by a bound in `a::bar`
   --> $DIR/closure-return-type-must-be-sized.rs:14:19
    |
 LL |     pub fn bar<F: FnOnce() -> R, R: ?Sized>() {}
-   |                   ^^^^^^^^^^^^^ required by this bound in `a::bar`
+   |                   ^^^^^^^^^^^^^ required by this bound in `bar`
 
 error[E0277]: the size for values of type `dyn A` cannot be known at compilation time
   --> $DIR/closure-return-type-must-be-sized.rs:56:5
@@ -51,7 +51,7 @@ note: required by a bound in `b::bar`
   --> $DIR/closure-return-type-must-be-sized.rs:28:19
    |
 LL |     pub fn bar<F: Fn() -> R, R: ?Sized>() {}
-   |                   ^^^^^^^^^ required by this bound in `b::bar`
+   |                   ^^^^^^^^^ required by this bound in `bar`
 
 error[E0277]: the size for values of type `dyn A` cannot be known at compilation time
   --> $DIR/closure-return-type-must-be-sized.rs:63:5
@@ -83,7 +83,7 @@ note: required by a bound in `c::bar`
   --> $DIR/closure-return-type-must-be-sized.rs:42:19
    |
 LL |     pub fn bar<F: FnMut() -> R, R: ?Sized>() {}
-   |                   ^^^^^^^^^^^^ required by this bound in `c::bar`
+   |                   ^^^^^^^^^^^^ required by this bound in `bar`
 
 error[E0277]: the size for values of type `dyn A` cannot be known at compilation time
   --> $DIR/closure-return-type-must-be-sized.rs:70:5
index 9c70bbc85acfab96b5d79c0fdf61647951913308..7ce061cd388c99602a40e9b62043fc9929372abe 100644 (file)
@@ -1,5 +1,7 @@
+#![feature(type_ascription)]
+
 fn main() {
-    2: n([u8; || 1])
+    type_ascribe!(2, n([u8; || 1]))
     //~^ ERROR cannot find type `n` in this scope
     //~| ERROR mismatched types
 }
index 1e102cc9805bd6879debae5b68465b804caa84af..a482750fbd016bf61dcb0383277d3991a8b9d10f 100644 (file)
@@ -1,21 +1,26 @@
 error[E0412]: cannot find type `n` in this scope
-  --> $DIR/issue-90871.rs:2:8
+  --> $DIR/issue-90871.rs:4:22
    |
-LL |     2: n([u8; || 1])
-   |        ^ expecting a type here because of type ascription
+LL |     type_ascribe!(2, n([u8; || 1]))
+   |                      ^ help: a trait with a similar name exists: `Fn`
+   |
+  ::: $SRC_DIR/core/src/ops/function.rs:LL:COL
+   |
+LL | pub trait Fn<Args: Tuple>: FnMut<Args> {
+   | -------------------------------------- similarly named trait `Fn` defined here
 
 error[E0308]: mismatched types
-  --> $DIR/issue-90871.rs:2:15
+  --> $DIR/issue-90871.rs:4:29
    |
-LL |     2: n([u8; || 1])
-   |               ^^^^ expected `usize`, found closure
+LL |     type_ascribe!(2, n([u8; || 1]))
+   |                             ^^^^ expected `usize`, found closure
    |
    = note: expected type `usize`
-           found closure `[closure@$DIR/issue-90871.rs:2:15: 2:17]`
+           found closure `[closure@$DIR/issue-90871.rs:4:29: 4:31]`
 help: use parentheses to call this closure
    |
-LL |     2: n([u8; (|| 1)()])
-   |               +    +++
+LL |     type_ascribe!(2, n([u8; (|| 1)()]))
+   |                             +    +++
 
 error: aborting due to 2 previous errors
 
index c139e823c2aef64e07f1b01528e7aa99e21e51c1..d7b11317ad5a8029067341d5874c9f48259beb1e 100644 (file)
@@ -6,27 +6,27 @@
 use std::fmt::Debug;
 
 pub fn main() {
-    let _ = box { [1, 2, 3] }: Box<[i32]>; //~ ERROR mismatched types
-    let _ = box if true { [1, 2, 3] } else { [1, 3, 4] }: Box<[i32]>; //~ ERROR mismatched types
-    let _ = box match true { true => [1, 2, 3], false => [1, 3, 4] }: Box<[i32]>;
+    let _ = type_ascribe!(box { [1, 2, 3] }, Box<[i32]>); //~ ERROR mismatched types
+    let _ = type_ascribe!(box if true { [1, 2, 3] } else { [1, 3, 4] }, Box<[i32]>); //~ ERROR mismatched types
+    let _ = type_ascribe!(box match true { true => [1, 2, 3], false => [1, 3, 4] }, Box<[i32]>);
     //~^ ERROR mismatched types
-    let _ = box { |x| (x as u8) }: Box<dyn Fn(i32) -> _>; //~ ERROR mismatched types
-    let _ = box if true { false } else { true }: Box<dyn Debug>; //~ ERROR mismatched types
-    let _ = box match true { true => 'a', false => 'b' }: Box<dyn Debug>; //~ ERROR mismatched types
+    let _ = type_ascribe!(box { |x| (x as u8) }, Box<dyn Fn(i32) -> _>); //~ ERROR mismatched types
+    let _ = type_ascribe!(box if true { false } else { true }, Box<dyn Debug>); //~ ERROR mismatched types
+    let _ = type_ascribe!(box match true { true => 'a', false => 'b' }, Box<dyn Debug>); //~ ERROR mismatched types
 
-    let _ = &{ [1, 2, 3] }: &[i32]; //~ ERROR mismatched types
-    let _ = &if true { [1, 2, 3] } else { [1, 3, 4] }: &[i32]; //~ ERROR mismatched types
-    let _ = &match true { true => [1, 2, 3], false => [1, 3, 4] }: &[i32];
+    let _ = type_ascribe!(&{ [1, 2, 3] }, &[i32]); //~ ERROR mismatched types
+    let _ = type_ascribe!(&if true { [1, 2, 3] } else { [1, 3, 4] }, &[i32]); //~ ERROR mismatched types
+    let _ = type_ascribe!(&match true { true => [1, 2, 3], false => [1, 3, 4] }, &[i32]);
     //~^ ERROR mismatched types
-    let _ = &{ |x| (x as u8) }: &dyn Fn(i32) -> _; //~ ERROR mismatched types
-    let _ = &if true { false } else { true }: &dyn Debug; //~ ERROR mismatched types
-    let _ = &match true { true => 'a', false => 'b' }: &dyn Debug; //~ ERROR mismatched types
+    let _ = type_ascribe!(&{ |x| (x as u8) }, &dyn Fn(i32) -> _); //~ ERROR mismatched types
+    let _ = type_ascribe!(&if true { false } else { true }, &dyn Debug); //~ ERROR mismatched types
+    let _ = type_ascribe!(&match true { true => 'a', false => 'b' }, &dyn Debug); //~ ERROR mismatched types
 
-    let _ = Box::new([1, 2, 3]): Box<[i32]>; //~ ERROR mismatched types
-    let _ = Box::new(|x| (x as u8)): Box<dyn Fn(i32) -> _>; //~ ERROR mismatched types
+    let _ = type_ascribe!(Box::new([1, 2, 3]), Box<[i32]>); //~ ERROR mismatched types
+    let _ = type_ascribe!(Box::new(|x| (x as u8)), Box<dyn Fn(i32) -> _>); //~ ERROR mismatched types
 
-    let _ = vec![
+    let _ = type_ascribe!(vec![
         Box::new(|x| (x as u8)),
         box |x| (x as i16 as u8),
-    ]: Vec<Box<dyn Fn(i32) -> _>>;
+    ], Vec<Box<dyn Fn(i32) -> _>>);
 }
index 9d614e610ad86fd1fedabd237d7b149804c9d95f..44968244c4d051bf5c8fa3b1f29912a6814cb023 100644 (file)
 error[E0308]: mismatched types
-  --> $DIR/coerce-expect-unsized-ascribed.rs:9:13
+  --> $DIR/coerce-expect-unsized-ascribed.rs:9:27
    |
-LL |     let _ = box { [1, 2, 3] }: Box<[i32]>;
-   |             ^^^^^^^^^^^^^^^^^ expected slice `[i32]`, found array `[i32; 3]`
+LL |     let _ = type_ascribe!(box { [1, 2, 3] }, Box<[i32]>);
+   |                           ^^^^^^^^^^^^^^^^^ expected slice `[i32]`, found array `[i32; 3]`
    |
    = note: expected struct `Box<[i32]>`
               found struct `Box<[i32; 3]>`
 
 error[E0308]: mismatched types
-  --> $DIR/coerce-expect-unsized-ascribed.rs:10:13
+  --> $DIR/coerce-expect-unsized-ascribed.rs:10:27
    |
-LL |     let _ = box if true { [1, 2, 3] } else { [1, 3, 4] }: Box<[i32]>;
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected slice `[i32]`, found array `[i32; 3]`
+LL |     let _ = type_ascribe!(box if true { [1, 2, 3] } else { [1, 3, 4] }, Box<[i32]>);
+   |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected slice `[i32]`, found array `[i32; 3]`
    |
    = note: expected struct `Box<[i32]>`
               found struct `Box<[i32; 3]>`
 
 error[E0308]: mismatched types
-  --> $DIR/coerce-expect-unsized-ascribed.rs:11:13
+  --> $DIR/coerce-expect-unsized-ascribed.rs:11:27
    |
-LL |     let _ = box match true { true => [1, 2, 3], false => [1, 3, 4] }: Box<[i32]>;
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected slice `[i32]`, found array `[i32; 3]`
+LL |     let _ = type_ascribe!(box match true { true => [1, 2, 3], false => [1, 3, 4] }, Box<[i32]>);
+   |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected slice `[i32]`, found array `[i32; 3]`
    |
    = note: expected struct `Box<[i32]>`
               found struct `Box<[i32; 3]>`
 
 error[E0308]: mismatched types
-  --> $DIR/coerce-expect-unsized-ascribed.rs:13:13
+  --> $DIR/coerce-expect-unsized-ascribed.rs:13:27
    |
-LL |     let _ = box { |x| (x as u8) }: Box<dyn Fn(i32) -> _>;
-   |             ^^^^^^^^^^^^^^^^^^^^^ expected trait object `dyn Fn`, found closure
+LL |     let _ = type_ascribe!(box { |x| (x as u8) }, Box<dyn Fn(i32) -> _>);
+   |                           ^^^^^^^^^^^^^^^^^^^^^ expected trait object `dyn Fn`, found closure
    |
    = note: expected struct `Box<dyn Fn(i32) -> u8>`
-              found struct `Box<[closure@$DIR/coerce-expect-unsized-ascribed.rs:13:19: 13:22]>`
+              found struct `Box<[closure@$DIR/coerce-expect-unsized-ascribed.rs:13:33: 13:36]>`
 
 error[E0308]: mismatched types
-  --> $DIR/coerce-expect-unsized-ascribed.rs:14:13
+  --> $DIR/coerce-expect-unsized-ascribed.rs:14:27
    |
-LL |     let _ = box if true { false } else { true }: Box<dyn Debug>;
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected trait object `dyn Debug`, found `bool`
+LL |     let _ = type_ascribe!(box if true { false } else { true }, Box<dyn Debug>);
+   |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected trait object `dyn Debug`, found `bool`
    |
    = note: expected struct `Box<dyn Debug>`
               found struct `Box<bool>`
 
 error[E0308]: mismatched types
-  --> $DIR/coerce-expect-unsized-ascribed.rs:15:13
+  --> $DIR/coerce-expect-unsized-ascribed.rs:15:27
    |
-LL |     let _ = box match true { true => 'a', false => 'b' }: Box<dyn Debug>;
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected trait object `dyn Debug`, found `char`
+LL |     let _ = type_ascribe!(box match true { true => 'a', false => 'b' }, Box<dyn Debug>);
+   |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected trait object `dyn Debug`, found `char`
    |
    = note: expected struct `Box<dyn Debug>`
               found struct `Box<char>`
 
 error[E0308]: mismatched types
-  --> $DIR/coerce-expect-unsized-ascribed.rs:17:13
+  --> $DIR/coerce-expect-unsized-ascribed.rs:17:27
    |
-LL |     let _ = &{ [1, 2, 3] }: &[i32];
-   |             ^^^^^^^^^^^^^^ expected slice `[i32]`, found array `[i32; 3]`
+LL |     let _ = type_ascribe!(&{ [1, 2, 3] }, &[i32]);
+   |                           ^^^^^^^^^^^^^^ expected slice `[i32]`, found array `[i32; 3]`
    |
    = note: expected reference `&[i32]`
               found reference `&[i32; 3]`
 
 error[E0308]: mismatched types
-  --> $DIR/coerce-expect-unsized-ascribed.rs:18:13
+  --> $DIR/coerce-expect-unsized-ascribed.rs:18:27
    |
-LL |     let _ = &if true { [1, 2, 3] } else { [1, 3, 4] }: &[i32];
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected slice `[i32]`, found array `[i32; 3]`
+LL |     let _ = type_ascribe!(&if true { [1, 2, 3] } else { [1, 3, 4] }, &[i32]);
+   |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected slice `[i32]`, found array `[i32; 3]`
    |
    = note: expected reference `&[i32]`
               found reference `&[i32; 3]`
 
 error[E0308]: mismatched types
-  --> $DIR/coerce-expect-unsized-ascribed.rs:19:13
+  --> $DIR/coerce-expect-unsized-ascribed.rs:19:27
    |
-LL |     let _ = &match true { true => [1, 2, 3], false => [1, 3, 4] }: &[i32];
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected slice `[i32]`, found array `[i32; 3]`
+LL |     let _ = type_ascribe!(&match true { true => [1, 2, 3], false => [1, 3, 4] }, &[i32]);
+   |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected slice `[i32]`, found array `[i32; 3]`
    |
    = note: expected reference `&[i32]`
               found reference `&[i32; 3]`
 
 error[E0308]: mismatched types
-  --> $DIR/coerce-expect-unsized-ascribed.rs:21:13
+  --> $DIR/coerce-expect-unsized-ascribed.rs:21:27
    |
-LL |     let _ = &{ |x| (x as u8) }: &dyn Fn(i32) -> _;
-   |             ^^^^^^^^^^^^^^^^^^ expected trait object `dyn Fn`, found closure
+LL |     let _ = type_ascribe!(&{ |x| (x as u8) }, &dyn Fn(i32) -> _);
+   |                           ^^^^^^^^^^^^^^^^^^ expected trait object `dyn Fn`, found closure
    |
    = note: expected reference `&dyn Fn(i32) -> u8`
-              found reference `&[closure@$DIR/coerce-expect-unsized-ascribed.rs:21:16: 21:19]`
+              found reference `&[closure@$DIR/coerce-expect-unsized-ascribed.rs:21:30: 21:33]`
 
 error[E0308]: mismatched types
-  --> $DIR/coerce-expect-unsized-ascribed.rs:22:13
+  --> $DIR/coerce-expect-unsized-ascribed.rs:22:27
    |
-LL |     let _ = &if true { false } else { true }: &dyn Debug;
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected trait object `dyn Debug`, found `bool`
+LL |     let _ = type_ascribe!(&if true { false } else { true }, &dyn Debug);
+   |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected trait object `dyn Debug`, found `bool`
    |
    = note: expected reference `&dyn Debug`
               found reference `&bool`
 
 error[E0308]: mismatched types
-  --> $DIR/coerce-expect-unsized-ascribed.rs:23:13
+  --> $DIR/coerce-expect-unsized-ascribed.rs:23:27
    |
-LL |     let _ = &match true { true => 'a', false => 'b' }: &dyn Debug;
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected trait object `dyn Debug`, found `char`
+LL |     let _ = type_ascribe!(&match true { true => 'a', false => 'b' }, &dyn Debug);
+   |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected trait object `dyn Debug`, found `char`
    |
    = note: expected reference `&dyn Debug`
               found reference `&char`
 
 error[E0308]: mismatched types
-  --> $DIR/coerce-expect-unsized-ascribed.rs:25:13
+  --> $DIR/coerce-expect-unsized-ascribed.rs:25:27
    |
-LL |     let _ = Box::new([1, 2, 3]): Box<[i32]>;
-   |             ^^^^^^^^^^^^^^^^^^^ expected slice `[i32]`, found array `[i32; 3]`
+LL |     let _ = type_ascribe!(Box::new([1, 2, 3]), Box<[i32]>);
+   |                           ^^^^^^^^^^^^^^^^^^^ expected slice `[i32]`, found array `[i32; 3]`
    |
    = note: expected struct `Box<[i32]>`
               found struct `Box<[i32; 3]>`
 
 error[E0308]: mismatched types
-  --> $DIR/coerce-expect-unsized-ascribed.rs:26:13
+  --> $DIR/coerce-expect-unsized-ascribed.rs:26:27
    |
-LL |     let _ = Box::new(|x| (x as u8)): Box<dyn Fn(i32) -> _>;
-   |             ^^^^^^^^^^^^^^^^^^^^^^^ expected trait object `dyn Fn`, found closure
+LL |     let _ = type_ascribe!(Box::new(|x| (x as u8)), Box<dyn Fn(i32) -> _>);
+   |                           ^^^^^^^^^^^^^^^^^^^^^^^ expected trait object `dyn Fn`, found closure
    |
    = note: expected struct `Box<dyn Fn(i32) -> u8>`
-              found struct `Box<[closure@$DIR/coerce-expect-unsized-ascribed.rs:26:22: 26:25]>`
+              found struct `Box<[closure@$DIR/coerce-expect-unsized-ascribed.rs:26:36: 26:39]>`
 
 error: aborting due to 14 previous errors
 
index d4bd673b84e1b70083273e08d5ccae0a4a4b36b8..d5b4349c00f6f090078578a84fefd5fffa3fb040 100644 (file)
@@ -14,7 +14,7 @@ error: `cfg` predicate is not specified
   --> $DIR/cfg-attr-syntax-validation.rs:7:1
    |
 LL | #[cfg()]
-   | ^^^^^^^^
+   | ^^^^^^^^ help: expected syntax is: `cfg(/* predicate */)`
 
 error: multiple `cfg` predicates are specified
   --> $DIR/cfg-attr-syntax-validation.rs:10:10
index f2e7777ce681411bb79372ae32a58eb91276c56c..a46bd53520b539ff8dfb6558d770d58045533b81 100644 (file)
@@ -18,9 +18,7 @@ LL |
 LL |     1_u32
    |     ----- return type was inferred to be `u32` here
    |
-   = help: the following other types implement trait `Traitor<N, M>`:
-             <u32 as Traitor<N, 2>>
-             <u64 as Traitor<1, 2>>
+   = help: the trait `Traitor<N, 2>` is implemented for `u32`
 
 error[E0277]: the trait bound `u64: Traitor` is not satisfied
   --> $DIR/rp_impl_trait_fail.rs:21:13
@@ -31,9 +29,7 @@ LL |
 LL |     1_u64
    |     ----- return type was inferred to be `u64` here
    |
-   = help: the following other types implement trait `Traitor<N, M>`:
-             <u32 as Traitor<N, 2>>
-             <u64 as Traitor<1, 2>>
+   = help: the trait `Traitor<1, 2>` is implemented for `u64`
 
 error: aborting due to 3 previous errors
 
diff --git a/src/test/ui/const-generics/defaults/self-referential.rs b/src/test/ui/const-generics/defaults/self-referential.rs
new file mode 100644 (file)
index 0000000..14a870d
--- /dev/null
@@ -0,0 +1,4 @@
+trait Foo<const M: u8, const M: u8 = M> {}
+//~^ ERROR the name `M` is already used for a generic parameter in this item's generic parameters
+impl Foo<2> for () {}
+fn main() {}
diff --git a/src/test/ui/const-generics/defaults/self-referential.stderr b/src/test/ui/const-generics/defaults/self-referential.stderr
new file mode 100644 (file)
index 0000000..170c1f7
--- /dev/null
@@ -0,0 +1,11 @@
+error[E0403]: the name `M` is already used for a generic parameter in this item's generic parameters
+  --> $DIR/self-referential.rs:1:30
+   |
+LL | trait Foo<const M: u8, const M: u8 = M> {}
+   |                 -            ^ already used
+   |                 |
+   |                 first use of `M`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0403`.
index ada1050d35f35a3f6a26a78fab0127f7b456f2f6..cdf97bd88fd236cf10c097e75947f08356db71c3 100644 (file)
@@ -14,7 +14,7 @@ note: required by a bound in `use_trait_impl::assert_impl`
   --> $DIR/abstract-const-as-cast-3.rs:14:23
    |
 LL |     fn assert_impl<T: Trait>() {}
-   |                       ^^^^^ required by this bound in `use_trait_impl::assert_impl`
+   |                       ^^^^^ required by this bound in `assert_impl`
 
 error[E0308]: mismatched types
   --> $DIR/abstract-const-as-cast-3.rs:17:5
@@ -28,7 +28,7 @@ note: required by a bound in `use_trait_impl::assert_impl`
   --> $DIR/abstract-const-as-cast-3.rs:14:23
    |
 LL |     fn assert_impl<T: Trait>() {}
-   |                       ^^^^^ required by this bound in `use_trait_impl::assert_impl`
+   |                       ^^^^^ required by this bound in `assert_impl`
 
 error: unconstrained generic constant
   --> $DIR/abstract-const-as-cast-3.rs:20:19
@@ -46,7 +46,7 @@ note: required by a bound in `use_trait_impl::assert_impl`
   --> $DIR/abstract-const-as-cast-3.rs:14:23
    |
 LL |     fn assert_impl<T: Trait>() {}
-   |                       ^^^^^ required by this bound in `use_trait_impl::assert_impl`
+   |                       ^^^^^ required by this bound in `assert_impl`
 
 error[E0308]: mismatched types
   --> $DIR/abstract-const-as-cast-3.rs:20:5
@@ -60,7 +60,7 @@ note: required by a bound in `use_trait_impl::assert_impl`
   --> $DIR/abstract-const-as-cast-3.rs:14:23
    |
 LL |     fn assert_impl<T: Trait>() {}
-   |                       ^^^^^ required by this bound in `use_trait_impl::assert_impl`
+   |                       ^^^^^ required by this bound in `assert_impl`
 
 error[E0308]: mismatched types
   --> $DIR/abstract-const-as-cast-3.rs:23:5
@@ -74,7 +74,7 @@ note: required by a bound in `use_trait_impl::assert_impl`
   --> $DIR/abstract-const-as-cast-3.rs:14:23
    |
 LL |     fn assert_impl<T: Trait>() {}
-   |                       ^^^^^ required by this bound in `use_trait_impl::assert_impl`
+   |                       ^^^^^ required by this bound in `assert_impl`
 
 error[E0308]: mismatched types
   --> $DIR/abstract-const-as-cast-3.rs:25:5
@@ -88,7 +88,7 @@ note: required by a bound in `use_trait_impl::assert_impl`
   --> $DIR/abstract-const-as-cast-3.rs:14:23
    |
 LL |     fn assert_impl<T: Trait>() {}
-   |                       ^^^^^ required by this bound in `use_trait_impl::assert_impl`
+   |                       ^^^^^ required by this bound in `assert_impl`
 
 error: unconstrained generic constant
   --> $DIR/abstract-const-as-cast-3.rs:35:19
@@ -106,7 +106,7 @@ note: required by a bound in `use_trait_impl_2::assert_impl`
   --> $DIR/abstract-const-as-cast-3.rs:32:23
    |
 LL |     fn assert_impl<T: Trait>() {}
-   |                       ^^^^^ required by this bound in `use_trait_impl_2::assert_impl`
+   |                       ^^^^^ required by this bound in `assert_impl`
 
 error[E0308]: mismatched types
   --> $DIR/abstract-const-as-cast-3.rs:35:5
@@ -120,7 +120,7 @@ note: required by a bound in `use_trait_impl_2::assert_impl`
   --> $DIR/abstract-const-as-cast-3.rs:32:23
    |
 LL |     fn assert_impl<T: Trait>() {}
-   |                       ^^^^^ required by this bound in `use_trait_impl_2::assert_impl`
+   |                       ^^^^^ required by this bound in `assert_impl`
 
 error: unconstrained generic constant
   --> $DIR/abstract-const-as-cast-3.rs:38:19
@@ -138,7 +138,7 @@ note: required by a bound in `use_trait_impl_2::assert_impl`
   --> $DIR/abstract-const-as-cast-3.rs:32:23
    |
 LL |     fn assert_impl<T: Trait>() {}
-   |                       ^^^^^ required by this bound in `use_trait_impl_2::assert_impl`
+   |                       ^^^^^ required by this bound in `assert_impl`
 
 error[E0308]: mismatched types
   --> $DIR/abstract-const-as-cast-3.rs:38:5
@@ -152,7 +152,7 @@ note: required by a bound in `use_trait_impl_2::assert_impl`
   --> $DIR/abstract-const-as-cast-3.rs:32:23
    |
 LL |     fn assert_impl<T: Trait>() {}
-   |                       ^^^^^ required by this bound in `use_trait_impl_2::assert_impl`
+   |                       ^^^^^ required by this bound in `assert_impl`
 
 error[E0308]: mismatched types
   --> $DIR/abstract-const-as-cast-3.rs:41:5
@@ -166,7 +166,7 @@ note: required by a bound in `use_trait_impl_2::assert_impl`
   --> $DIR/abstract-const-as-cast-3.rs:32:23
    |
 LL |     fn assert_impl<T: Trait>() {}
-   |                       ^^^^^ required by this bound in `use_trait_impl_2::assert_impl`
+   |                       ^^^^^ required by this bound in `assert_impl`
 
 error[E0308]: mismatched types
   --> $DIR/abstract-const-as-cast-3.rs:43:5
@@ -180,7 +180,7 @@ note: required by a bound in `use_trait_impl_2::assert_impl`
   --> $DIR/abstract-const-as-cast-3.rs:32:23
    |
 LL |     fn assert_impl<T: Trait>() {}
-   |                       ^^^^^ required by this bound in `use_trait_impl_2::assert_impl`
+   |                       ^^^^^ required by this bound in `assert_impl`
 
 error: aborting due to 12 previous errors
 
diff --git a/src/test/ui/const-generics/generic_const_exprs/const_kind_expr/wf_obligation.rs b/src/test/ui/const-generics/generic_const_exprs/const_kind_expr/wf_obligation.rs
new file mode 100644 (file)
index 0000000..6093fc7
--- /dev/null
@@ -0,0 +1,22 @@
+#![feature(generic_const_exprs, generic_arg_infer)]
+#![allow(incomplete_features)]
+
+// minimized repro for #105205
+//
+// the `foo::<_, L>` call results in a `WellFormed(_)` obligation and a
+// `ConstEvaluatable(Unevaluated(_ + 1 + L))` obligation. Attempting to fulfill the latter
+// unifies the `_` with `Expr(L - 1)` from the paramenv which turns the `WellFormed`
+// obligation into `WellFormed(Expr(L - 1))`
+
+fn foo<const N: usize, const M: usize>(_: [(); N + 1 + M]) {}
+
+fn ice<const L: usize>()
+where
+    [(); (L - 1) + 1 + L]:,
+{
+    foo::<_, L>([(); L + 1 + L]);
+    //~^ ERROR: mismatched types
+    //~^^ ERROR: unconstrained generic constant
+}
+
+fn main() {}
diff --git a/src/test/ui/const-generics/generic_const_exprs/const_kind_expr/wf_obligation.stderr b/src/test/ui/const-generics/generic_const_exprs/const_kind_expr/wf_obligation.stderr
new file mode 100644 (file)
index 0000000..da51946
--- /dev/null
@@ -0,0 +1,20 @@
+error[E0308]: mismatched types
+  --> $DIR/wf_obligation.rs:17:17
+   |
+LL |     foo::<_, L>([(); L + 1 + L]);
+   |                 ^^^^^^^^^^^^^^^ expected `N + 1 + M`, found `L + 1 + L`
+   |
+   = note: expected constant `N + 1 + M`
+              found constant `L + 1 + L`
+
+error: unconstrained generic constant
+  --> $DIR/wf_obligation.rs:17:22
+   |
+LL |     foo::<_, L>([(); L + 1 + L]);
+   |                      ^^^^^^^^^
+   |
+   = help: try adding a `where` bound using this expression: `where [(); L + 1 + L]:`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/const-generics/generic_const_exprs/issue-105257.rs b/src/test/ui/const-generics/generic_const_exprs/issue-105257.rs
new file mode 100644 (file)
index 0000000..d8b23bc
--- /dev/null
@@ -0,0 +1,9 @@
+#![feature(generic_const_exprs)]
+#![allow(incomplete_features)]
+
+trait Trait<T> {
+    fn fnc<const N: usize = "">(&self) {} //~ERROR defaults for const parameters are only allowed in `struct`, `enum`, `type`, or `trait` definitions
+    fn foo<const N: usize = { std::mem::size_of::<T>() }>(&self) {} //~ERROR defaults for const parameters are only allowed in `struct`, `enum`, `type`, or `trait` definitions
+}
+
+fn main() {}
diff --git a/src/test/ui/const-generics/generic_const_exprs/issue-105257.stderr b/src/test/ui/const-generics/generic_const_exprs/issue-105257.stderr
new file mode 100644 (file)
index 0000000..ed7a8cb
--- /dev/null
@@ -0,0 +1,14 @@
+error: defaults for const parameters are only allowed in `struct`, `enum`, `type`, or `trait` definitions
+  --> $DIR/issue-105257.rs:5:12
+   |
+LL |     fn fnc<const N: usize = "">(&self) {}
+   |            ^^^^^^^^^^^^^^^^^^^
+
+error: defaults for const parameters are only allowed in `struct`, `enum`, `type`, or `trait` definitions
+  --> $DIR/issue-105257.rs:6:12
+   |
+LL |     fn foo<const N: usize = { std::mem::size_of::<T>() }>(&self) {}
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 2 previous errors
+
index c90774e944f1f48d690099893a5025992b15054c..029528c3a8172772da0aa816061918b95613641e 100644 (file)
@@ -2,7 +2,9 @@ error[E0308]: mismatched types
   --> $DIR/issue-79518-default_trait_method_normalization.rs:16:32
    |
 LL |         Self::AssocInstance == [(); std::mem::size_of::<Self::Assoc>()];
-   |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected associated type, found array `[(); _]`
+   |         -------------------    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected associated type, found array `[(); _]`
+   |         |
+   |         expected because this is `<Self as Foo>::Assoc`
    |
    = note: expected associated type `<Self as Foo>::Assoc`
                         found array `[(); _]`
index 1b502642eb7d03f12f881017b5547aa13c8b51da..bf1b411ee7ccfdffe5485386a183c7ac81dd9376 100644 (file)
@@ -2,15 +2,18 @@ error[E0080]: evaluation of `Inline::<dyn std::fmt::Debug>::{constant#0}` failed
   --> $SRC_DIR/core/src/mem/mod.rs:LL:COL
    |
 LL |     intrinsics::size_of::<T>()
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |     |
-   |     size_of called on unsized type `dyn Debug`
-   |     inside `std::mem::size_of::<dyn Debug>` at $SRC_DIR/core/src/mem/mod.rs:LL:COL
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^ size_of called on unsized type `dyn Debug`
+   |
+note: inside `std::mem::size_of::<dyn Debug>`
+  --> $SRC_DIR/core/src/mem/mod.rs:LL:COL
    |
-  ::: $DIR/issue-80742.rs:22:10
+LL |     intrinsics::size_of::<T>()
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
+note: inside `Inline::<dyn Debug>::{constant#0}`
+  --> $DIR/issue-80742.rs:22:10
    |
 LL |     [u8; size_of::<T>() + 1]: ,
-   |          -------------- inside `Inline::<dyn Debug>::{constant#0}` at $DIR/issue-80742.rs:22:10
+   |          ^^^^^^^^^^^^^^
 
 error[E0599]: the function or associated item `new` exists for struct `Inline<dyn Debug>`, but its trait bounds were not satisfied
   --> $DIR/issue-80742.rs:30:36
@@ -33,15 +36,18 @@ error[E0080]: evaluation of `Inline::<dyn std::fmt::Debug>::{constant#0}` failed
   --> $SRC_DIR/core/src/mem/mod.rs:LL:COL
    |
 LL |     intrinsics::size_of::<T>()
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |     |
-   |     size_of called on unsized type `dyn Debug`
-   |     inside `std::mem::size_of::<dyn Debug>` at $SRC_DIR/core/src/mem/mod.rs:LL:COL
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^ size_of called on unsized type `dyn Debug`
+   |
+note: inside `std::mem::size_of::<dyn Debug>`
+  --> $SRC_DIR/core/src/mem/mod.rs:LL:COL
    |
-  ::: $DIR/issue-80742.rs:14:10
+LL |     intrinsics::size_of::<T>()
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
+note: inside `Inline::<dyn Debug>::{constant#0}`
+  --> $DIR/issue-80742.rs:14:10
    |
 LL |     [u8; size_of::<T>() + 1]: ,
-   |          -------------- inside `Inline::<dyn Debug>::{constant#0}` at $DIR/issue-80742.rs:14:10
+   |          ^^^^^^^^^^^^^^
 
 error[E0277]: the size for values of type `dyn Debug` cannot be known at compilation time
   --> $DIR/issue-80742.rs:30:15
diff --git a/src/test/ui/const-generics/generic_const_exprs/normed_to_param_is_evaluatable.rs b/src/test/ui/const-generics/generic_const_exprs/normed_to_param_is_evaluatable.rs
new file mode 100644 (file)
index 0000000..b37b354
--- /dev/null
@@ -0,0 +1,12 @@
+// check-pass
+#![feature(generic_const_exprs)]
+#![allow(incomplete_features, unused_braces)]
+
+#[rustfmt::skip]
+fn foo<const N: usize>() {
+    bar::<{{{{{{ N }}}}}}>();
+}
+
+fn bar<const N: usize>() {}
+
+fn main() {}
index f3ce357c2bb8d9b8f221d0f9e436b36c4a9eb84e..d4b486376cac822ddf8dd2dc2f7825755b1773f1 100644 (file)
@@ -1,14 +1,19 @@
 error[E0080]: evaluation of constant value failed
   --> $DIR/issue-100313.rs:10:13
    |
+LL |             *(B as *const bool as *mut bool) = false;
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ writing to alloc7 which is read-only
+   |
+note: inside `T::<&true>::set_false`
+  --> $DIR/issue-100313.rs:10:13
+   |
 LL |             *(B as *const bool as *mut bool) = false;
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |             |
-   |             writing to alloc7 which is read-only
-   |             inside `T::<&true>::set_false` at $DIR/issue-100313.rs:10:13
-...
+note: inside `_`
+  --> $DIR/issue-100313.rs:18:5
+   |
 LL |     x.set_false();
-   |     ------------- inside `_` at $DIR/issue-100313.rs:18:5
+   |     ^^^^^^^^^^^^^
 
 error: aborting due to previous error
 
index 8978ab436d07d9f54ff118893cc629a5169613a9..563f3ffd6744f0650cab1cd129d4688a99440c0f 100644 (file)
@@ -2,43 +2,52 @@ error[E0080]: could not evaluate static initializer
   --> $SRC_DIR/core/src/slice/raw.rs:LL:COL
    |
 LL |         &*ptr::slice_from_raw_parts(data, len)
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |         |
-   |         dereferencing pointer failed: null pointer is a dangling pointer (it has no provenance)
-   |         inside `std::slice::from_raw_parts::<'_, u32>` at $SRC_DIR/core/src/slice/raw.rs:LL:COL
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ dereferencing pointer failed: null pointer is a dangling pointer (it has no provenance)
+   |
+note: inside `std::slice::from_raw_parts::<'_, u32>`
+  --> $SRC_DIR/core/src/slice/raw.rs:LL:COL
    |
-  ::: $DIR/forbidden_slices.rs:18:34
+LL |         &*ptr::slice_from_raw_parts(data, len)
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+note: inside `S0`
+  --> $DIR/forbidden_slices.rs:18:34
    |
 LL | pub static S0: &[u32] = unsafe { from_raw_parts(ptr::null(), 0) };
-   |                                  ------------------------------ inside `S0` at $DIR/forbidden_slices.rs:18:34
+   |                                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0080]: could not evaluate static initializer
   --> $SRC_DIR/core/src/slice/raw.rs:LL:COL
    |
 LL |         &*ptr::slice_from_raw_parts(data, len)
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |         |
-   |         dereferencing pointer failed: null pointer is a dangling pointer (it has no provenance)
-   |         inside `std::slice::from_raw_parts::<'_, ()>` at $SRC_DIR/core/src/slice/raw.rs:LL:COL
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ dereferencing pointer failed: null pointer is a dangling pointer (it has no provenance)
+   |
+note: inside `std::slice::from_raw_parts::<'_, ()>`
+  --> $SRC_DIR/core/src/slice/raw.rs:LL:COL
    |
-  ::: $DIR/forbidden_slices.rs:19:33
+LL |         &*ptr::slice_from_raw_parts(data, len)
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+note: inside `S1`
+  --> $DIR/forbidden_slices.rs:19:33
    |
 LL | pub static S1: &[()] = unsafe { from_raw_parts(ptr::null(), 0) };
-   |                                 ------------------------------ inside `S1` at $DIR/forbidden_slices.rs:19:33
+   |                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0080]: could not evaluate static initializer
   --> $SRC_DIR/core/src/slice/raw.rs:LL:COL
    |
 LL |         &*ptr::slice_from_raw_parts(data, len)
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |         |
-   |         dereferencing pointer failed: ALLOC_ID has size 4, so pointer to 8 bytes starting at offset 0 is out-of-bounds
-   |         inside `std::slice::from_raw_parts::<'_, u32>` at $SRC_DIR/core/src/slice/raw.rs:LL:COL
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ dereferencing pointer failed: ALLOC_ID has size 4, so pointer to 8 bytes starting at offset 0 is out-of-bounds
+   |
+note: inside `std::slice::from_raw_parts::<'_, u32>`
+  --> $SRC_DIR/core/src/slice/raw.rs:LL:COL
    |
-  ::: $DIR/forbidden_slices.rs:22:34
+LL |         &*ptr::slice_from_raw_parts(data, len)
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+note: inside `S2`
+  --> $DIR/forbidden_slices.rs:22:34
    |
 LL | pub static S2: &[u32] = unsafe { from_raw_parts(&D0, 2) };
-   |                                  ---------------------- inside `S2` at $DIR/forbidden_slices.rs:22:34
+   |                                  ^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0080]: it is undefined behavior to use this value
   --> $DIR/forbidden_slices.rs:25:1
@@ -89,72 +98,85 @@ error[E0080]: could not evaluate static initializer
   --> $SRC_DIR/core/src/slice/raw.rs:LL:COL
    |
 LL |         &*ptr::slice_from_raw_parts(data, len)
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |         |
-   |         dereferencing pointer failed: ALLOC_ID has size 8, so pointer to 8 bytes starting at offset 1 is out-of-bounds
-   |         inside `std::slice::from_raw_parts::<'_, u64>` at $SRC_DIR/core/src/slice/raw.rs:LL:COL
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ dereferencing pointer failed: ALLOC_ID has size 8, so pointer to 8 bytes starting at offset 1 is out-of-bounds
    |
-  ::: $DIR/forbidden_slices.rs:43:5
+note: inside `std::slice::from_raw_parts::<'_, u64>`
+  --> $SRC_DIR/core/src/slice/raw.rs:LL:COL
+   |
+LL |         &*ptr::slice_from_raw_parts(data, len)
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+note: inside `S8`
+  --> $DIR/forbidden_slices.rs:43:5
    |
 LL |     from_raw_parts(ptr, 1)
-   |     ---------------------- inside `S8` at $DIR/forbidden_slices.rs:43:5
+   |     ^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0080]: could not evaluate static initializer
   --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
    |
 LL |         unsafe { intrinsics::ptr_offset_from_unsigned(self, origin) }
-   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |                  |
-   |                  out-of-bounds offset_from: null pointer is a dangling pointer (it has no provenance)
-   |                  inside `ptr::const_ptr::<impl *const u32>::sub_ptr` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
+   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds offset_from: null pointer is a dangling pointer (it has no provenance)
    |
-  ::: $SRC_DIR/core/src/slice/raw.rs:LL:COL
+note: inside `ptr::const_ptr::<impl *const u32>::sub_ptr`
+  --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
    |
-LL |     unsafe { from_raw_parts(range.start, range.end.sub_ptr(range.start)) }
-   |                                          ------------------------------ inside `from_ptr_range::<'_, u32>` at $SRC_DIR/core/src/slice/raw.rs:LL:COL
+LL |         unsafe { intrinsics::ptr_offset_from_unsigned(self, origin) }
+   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+note: inside `from_ptr_range::<'_, u32>`
+  --> $SRC_DIR/core/src/slice/raw.rs:LL:COL
    |
-  ::: $DIR/forbidden_slices.rs:46:34
+LL |     unsafe { from_raw_parts(range.start, range.end.sub_ptr(range.start)) }
+   |                                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+note: inside `R0`
+  --> $DIR/forbidden_slices.rs:46:34
    |
 LL | pub static R0: &[u32] = unsafe { from_ptr_range(ptr::null()..ptr::null()) };
-   |                                  ---------------------------------------- inside `R0` at $DIR/forbidden_slices.rs:46:34
+   |                                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0080]: could not evaluate static initializer
   --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
    |
 LL |         assert!(0 < pointee_size && pointee_size <= isize::MAX as usize);
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |         |
-   |         the evaluated program panicked at 'assertion failed: 0 < pointee_size && pointee_size <= isize::MAX as usize', $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
-   |         inside `ptr::const_ptr::<impl *const ()>::sub_ptr` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'assertion failed: 0 < pointee_size && pointee_size <= isize::MAX as usize', $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
    |
-  ::: $SRC_DIR/core/src/slice/raw.rs:LL:COL
+note: inside `ptr::const_ptr::<impl *const ()>::sub_ptr`
+  --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
    |
-LL |     unsafe { from_raw_parts(range.start, range.end.sub_ptr(range.start)) }
-   |                                          ------------------------------ inside `from_ptr_range::<'_, ()>` at $SRC_DIR/core/src/slice/raw.rs:LL:COL
+LL |         assert!(0 < pointee_size && pointee_size <= isize::MAX as usize);
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+note: inside `from_ptr_range::<'_, ()>`
+  --> $SRC_DIR/core/src/slice/raw.rs:LL:COL
    |
-  ::: $DIR/forbidden_slices.rs:47:33
+LL |     unsafe { from_raw_parts(range.start, range.end.sub_ptr(range.start)) }
+   |                                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+note: inside `R1`
+  --> $DIR/forbidden_slices.rs:47:33
    |
 LL | pub static R1: &[()] = unsafe { from_ptr_range(ptr::null()..ptr::null()) };
-   |                                 ---------------------------------------- inside `R1` at $DIR/forbidden_slices.rs:47:33
-   |
+   |                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    = note: this error originates in the macro `assert` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error[E0080]: could not evaluate static initializer
   --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
    |
+LL |         unsafe { intrinsics::offset(self, count) }
+   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer arithmetic: ALLOC_ID has size 4, so pointer to 8 bytes starting at offset 0 is out-of-bounds
+   |
+note: inside `ptr::const_ptr::<impl *const u32>::offset`
+  --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
+   |
 LL |         unsafe { intrinsics::offset(self, count) }
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |                  |
-   |                  out-of-bounds pointer arithmetic: ALLOC_ID has size 4, so pointer to 8 bytes starting at offset 0 is out-of-bounds
-   |                  inside `ptr::const_ptr::<impl *const u32>::offset` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
-...
-LL |         unsafe { self.offset(count as isize) }
-   |                  --------------------------- inside `ptr::const_ptr::<impl *const u32>::add` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
+note: inside `ptr::const_ptr::<impl *const u32>::add`
+  --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
    |
-  ::: $DIR/forbidden_slices.rs:50:25
+LL |         unsafe { self.offset(count as isize) }
+   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+note: inside `R2`
+  --> $DIR/forbidden_slices.rs:50:25
    |
 LL |     from_ptr_range(ptr..ptr.add(2))
-   |                         ---------- inside `R2` at $DIR/forbidden_slices.rs:50:25
+   |                         ^^^^^^^^^^
 
 error[E0080]: it is undefined behavior to use this value
   --> $DIR/forbidden_slices.rs:52:1
@@ -204,57 +226,68 @@ LL | pub static R7: &[u16] = unsafe {
 error[E0080]: could not evaluate static initializer
   --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
    |
+LL |         unsafe { intrinsics::offset(self, count) }
+   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer arithmetic: ALLOC_ID has size 8, so pointer to 8 bytes starting at offset 1 is out-of-bounds
+   |
+note: inside `ptr::const_ptr::<impl *const u64>::offset`
+  --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
+   |
 LL |         unsafe { intrinsics::offset(self, count) }
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |                  |
-   |                  out-of-bounds pointer arithmetic: ALLOC_ID has size 8, so pointer to 8 bytes starting at offset 1 is out-of-bounds
-   |                  inside `ptr::const_ptr::<impl *const u64>::offset` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
-...
-LL |         unsafe { self.offset(count as isize) }
-   |                  --------------------------- inside `ptr::const_ptr::<impl *const u64>::add` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
+note: inside `ptr::const_ptr::<impl *const u64>::add`
+  --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
    |
-  ::: $DIR/forbidden_slices.rs:74:25
+LL |         unsafe { self.offset(count as isize) }
+   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+note: inside `R8`
+  --> $DIR/forbidden_slices.rs:74:25
    |
 LL |     from_ptr_range(ptr..ptr.add(1))
-   |                         ---------- inside `R8` at $DIR/forbidden_slices.rs:74:25
+   |                         ^^^^^^^^^^
 
 error[E0080]: could not evaluate static initializer
   --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
    |
 LL |         unsafe { intrinsics::ptr_offset_from_unsigned(self, origin) }
-   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |                  |
-   |                  `ptr_offset_from_unsigned` called on pointers into different allocations
-   |                  inside `ptr::const_ptr::<impl *const u32>::sub_ptr` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
+   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `ptr_offset_from_unsigned` called on pointers into different allocations
    |
-  ::: $SRC_DIR/core/src/slice/raw.rs:LL:COL
+note: inside `ptr::const_ptr::<impl *const u32>::sub_ptr`
+  --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
    |
-LL |     unsafe { from_raw_parts(range.start, range.end.sub_ptr(range.start)) }
-   |                                          ------------------------------ inside `from_ptr_range::<'_, u32>` at $SRC_DIR/core/src/slice/raw.rs:LL:COL
+LL |         unsafe { intrinsics::ptr_offset_from_unsigned(self, origin) }
+   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+note: inside `from_ptr_range::<'_, u32>`
+  --> $SRC_DIR/core/src/slice/raw.rs:LL:COL
    |
-  ::: $DIR/forbidden_slices.rs:79:34
+LL |     unsafe { from_raw_parts(range.start, range.end.sub_ptr(range.start)) }
+   |                                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+note: inside `R9`
+  --> $DIR/forbidden_slices.rs:79:34
    |
 LL | pub static R9: &[u32] = unsafe { from_ptr_range(&D0..(&D0 as *const u32).add(1)) };
-   |                                  ----------------------------------------------- inside `R9` at $DIR/forbidden_slices.rs:79:34
+   |                                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0080]: could not evaluate static initializer
   --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
    |
 LL |         unsafe { intrinsics::ptr_offset_from_unsigned(self, origin) }
-   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |                  |
-   |                  `ptr_offset_from_unsigned` called on pointers into different allocations
-   |                  inside `ptr::const_ptr::<impl *const u32>::sub_ptr` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
+   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `ptr_offset_from_unsigned` called on pointers into different allocations
    |
-  ::: $SRC_DIR/core/src/slice/raw.rs:LL:COL
+note: inside `ptr::const_ptr::<impl *const u32>::sub_ptr`
+  --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
    |
-LL |     unsafe { from_raw_parts(range.start, range.end.sub_ptr(range.start)) }
-   |                                          ------------------------------ inside `from_ptr_range::<'_, u32>` at $SRC_DIR/core/src/slice/raw.rs:LL:COL
+LL |         unsafe { intrinsics::ptr_offset_from_unsigned(self, origin) }
+   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+note: inside `from_ptr_range::<'_, u32>`
+  --> $SRC_DIR/core/src/slice/raw.rs:LL:COL
    |
-  ::: $DIR/forbidden_slices.rs:80:35
+LL |     unsafe { from_raw_parts(range.start, range.end.sub_ptr(range.start)) }
+   |                                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+note: inside `R10`
+  --> $DIR/forbidden_slices.rs:80:35
    |
 LL | pub static R10: &[u32] = unsafe { from_ptr_range(&D0..&D0) };
-   |                                   ------------------------ inside `R10` at $DIR/forbidden_slices.rs:80:35
+   |                                   ^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to 18 previous errors
 
index db42b7c98307d229d350b1fcf5dfbec79e38b628..43529d57f4021aabc40869804ed85b177fece5ac 100644 (file)
@@ -2,43 +2,52 @@ error[E0080]: could not evaluate static initializer
   --> $SRC_DIR/core/src/slice/raw.rs:LL:COL
    |
 LL |         &*ptr::slice_from_raw_parts(data, len)
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |         |
-   |         dereferencing pointer failed: null pointer is a dangling pointer (it has no provenance)
-   |         inside `std::slice::from_raw_parts::<'_, u32>` at $SRC_DIR/core/src/slice/raw.rs:LL:COL
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ dereferencing pointer failed: null pointer is a dangling pointer (it has no provenance)
+   |
+note: inside `std::slice::from_raw_parts::<'_, u32>`
+  --> $SRC_DIR/core/src/slice/raw.rs:LL:COL
    |
-  ::: $DIR/forbidden_slices.rs:18:34
+LL |         &*ptr::slice_from_raw_parts(data, len)
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+note: inside `S0`
+  --> $DIR/forbidden_slices.rs:18:34
    |
 LL | pub static S0: &[u32] = unsafe { from_raw_parts(ptr::null(), 0) };
-   |                                  ------------------------------ inside `S0` at $DIR/forbidden_slices.rs:18:34
+   |                                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0080]: could not evaluate static initializer
   --> $SRC_DIR/core/src/slice/raw.rs:LL:COL
    |
 LL |         &*ptr::slice_from_raw_parts(data, len)
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |         |
-   |         dereferencing pointer failed: null pointer is a dangling pointer (it has no provenance)
-   |         inside `std::slice::from_raw_parts::<'_, ()>` at $SRC_DIR/core/src/slice/raw.rs:LL:COL
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ dereferencing pointer failed: null pointer is a dangling pointer (it has no provenance)
+   |
+note: inside `std::slice::from_raw_parts::<'_, ()>`
+  --> $SRC_DIR/core/src/slice/raw.rs:LL:COL
    |
-  ::: $DIR/forbidden_slices.rs:19:33
+LL |         &*ptr::slice_from_raw_parts(data, len)
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+note: inside `S1`
+  --> $DIR/forbidden_slices.rs:19:33
    |
 LL | pub static S1: &[()] = unsafe { from_raw_parts(ptr::null(), 0) };
-   |                                 ------------------------------ inside `S1` at $DIR/forbidden_slices.rs:19:33
+   |                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0080]: could not evaluate static initializer
   --> $SRC_DIR/core/src/slice/raw.rs:LL:COL
    |
 LL |         &*ptr::slice_from_raw_parts(data, len)
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |         |
-   |         dereferencing pointer failed: ALLOC_ID has size 4, so pointer to 8 bytes starting at offset 0 is out-of-bounds
-   |         inside `std::slice::from_raw_parts::<'_, u32>` at $SRC_DIR/core/src/slice/raw.rs:LL:COL
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ dereferencing pointer failed: ALLOC_ID has size 4, so pointer to 8 bytes starting at offset 0 is out-of-bounds
+   |
+note: inside `std::slice::from_raw_parts::<'_, u32>`
+  --> $SRC_DIR/core/src/slice/raw.rs:LL:COL
    |
-  ::: $DIR/forbidden_slices.rs:22:34
+LL |         &*ptr::slice_from_raw_parts(data, len)
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+note: inside `S2`
+  --> $DIR/forbidden_slices.rs:22:34
    |
 LL | pub static S2: &[u32] = unsafe { from_raw_parts(&D0, 2) };
-   |                                  ---------------------- inside `S2` at $DIR/forbidden_slices.rs:22:34
+   |                                  ^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0080]: it is undefined behavior to use this value
   --> $DIR/forbidden_slices.rs:25:1
@@ -89,72 +98,85 @@ error[E0080]: could not evaluate static initializer
   --> $SRC_DIR/core/src/slice/raw.rs:LL:COL
    |
 LL |         &*ptr::slice_from_raw_parts(data, len)
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |         |
-   |         dereferencing pointer failed: ALLOC_ID has size 8, so pointer to 8 bytes starting at offset 1 is out-of-bounds
-   |         inside `std::slice::from_raw_parts::<'_, u64>` at $SRC_DIR/core/src/slice/raw.rs:LL:COL
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ dereferencing pointer failed: ALLOC_ID has size 8, so pointer to 8 bytes starting at offset 1 is out-of-bounds
    |
-  ::: $DIR/forbidden_slices.rs:43:5
+note: inside `std::slice::from_raw_parts::<'_, u64>`
+  --> $SRC_DIR/core/src/slice/raw.rs:LL:COL
+   |
+LL |         &*ptr::slice_from_raw_parts(data, len)
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+note: inside `S8`
+  --> $DIR/forbidden_slices.rs:43:5
    |
 LL |     from_raw_parts(ptr, 1)
-   |     ---------------------- inside `S8` at $DIR/forbidden_slices.rs:43:5
+   |     ^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0080]: could not evaluate static initializer
   --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
    |
 LL |         unsafe { intrinsics::ptr_offset_from_unsigned(self, origin) }
-   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |                  |
-   |                  out-of-bounds offset_from: null pointer is a dangling pointer (it has no provenance)
-   |                  inside `ptr::const_ptr::<impl *const u32>::sub_ptr` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
+   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds offset_from: null pointer is a dangling pointer (it has no provenance)
    |
-  ::: $SRC_DIR/core/src/slice/raw.rs:LL:COL
+note: inside `ptr::const_ptr::<impl *const u32>::sub_ptr`
+  --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
    |
-LL |     unsafe { from_raw_parts(range.start, range.end.sub_ptr(range.start)) }
-   |                                          ------------------------------ inside `from_ptr_range::<'_, u32>` at $SRC_DIR/core/src/slice/raw.rs:LL:COL
+LL |         unsafe { intrinsics::ptr_offset_from_unsigned(self, origin) }
+   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+note: inside `from_ptr_range::<'_, u32>`
+  --> $SRC_DIR/core/src/slice/raw.rs:LL:COL
    |
-  ::: $DIR/forbidden_slices.rs:46:34
+LL |     unsafe { from_raw_parts(range.start, range.end.sub_ptr(range.start)) }
+   |                                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+note: inside `R0`
+  --> $DIR/forbidden_slices.rs:46:34
    |
 LL | pub static R0: &[u32] = unsafe { from_ptr_range(ptr::null()..ptr::null()) };
-   |                                  ---------------------------------------- inside `R0` at $DIR/forbidden_slices.rs:46:34
+   |                                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0080]: could not evaluate static initializer
   --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
    |
 LL |         assert!(0 < pointee_size && pointee_size <= isize::MAX as usize);
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |         |
-   |         the evaluated program panicked at 'assertion failed: 0 < pointee_size && pointee_size <= isize::MAX as usize', $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
-   |         inside `ptr::const_ptr::<impl *const ()>::sub_ptr` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'assertion failed: 0 < pointee_size && pointee_size <= isize::MAX as usize', $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
    |
-  ::: $SRC_DIR/core/src/slice/raw.rs:LL:COL
+note: inside `ptr::const_ptr::<impl *const ()>::sub_ptr`
+  --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
    |
-LL |     unsafe { from_raw_parts(range.start, range.end.sub_ptr(range.start)) }
-   |                                          ------------------------------ inside `from_ptr_range::<'_, ()>` at $SRC_DIR/core/src/slice/raw.rs:LL:COL
+LL |         assert!(0 < pointee_size && pointee_size <= isize::MAX as usize);
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+note: inside `from_ptr_range::<'_, ()>`
+  --> $SRC_DIR/core/src/slice/raw.rs:LL:COL
    |
-  ::: $DIR/forbidden_slices.rs:47:33
+LL |     unsafe { from_raw_parts(range.start, range.end.sub_ptr(range.start)) }
+   |                                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+note: inside `R1`
+  --> $DIR/forbidden_slices.rs:47:33
    |
 LL | pub static R1: &[()] = unsafe { from_ptr_range(ptr::null()..ptr::null()) };
-   |                                 ---------------------------------------- inside `R1` at $DIR/forbidden_slices.rs:47:33
-   |
+   |                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    = note: this error originates in the macro `assert` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error[E0080]: could not evaluate static initializer
   --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
    |
+LL |         unsafe { intrinsics::offset(self, count) }
+   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer arithmetic: ALLOC_ID has size 4, so pointer to 8 bytes starting at offset 0 is out-of-bounds
+   |
+note: inside `ptr::const_ptr::<impl *const u32>::offset`
+  --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
+   |
 LL |         unsafe { intrinsics::offset(self, count) }
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |                  |
-   |                  out-of-bounds pointer arithmetic: ALLOC_ID has size 4, so pointer to 8 bytes starting at offset 0 is out-of-bounds
-   |                  inside `ptr::const_ptr::<impl *const u32>::offset` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
-...
-LL |         unsafe { self.offset(count as isize) }
-   |                  --------------------------- inside `ptr::const_ptr::<impl *const u32>::add` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
+note: inside `ptr::const_ptr::<impl *const u32>::add`
+  --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
    |
-  ::: $DIR/forbidden_slices.rs:50:25
+LL |         unsafe { self.offset(count as isize) }
+   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+note: inside `R2`
+  --> $DIR/forbidden_slices.rs:50:25
    |
 LL |     from_ptr_range(ptr..ptr.add(2))
-   |                         ---------- inside `R2` at $DIR/forbidden_slices.rs:50:25
+   |                         ^^^^^^^^^^
 
 error[E0080]: it is undefined behavior to use this value
   --> $DIR/forbidden_slices.rs:52:1
@@ -204,57 +226,68 @@ LL | pub static R7: &[u16] = unsafe {
 error[E0080]: could not evaluate static initializer
   --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
    |
+LL |         unsafe { intrinsics::offset(self, count) }
+   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer arithmetic: ALLOC_ID has size 8, so pointer to 8 bytes starting at offset 1 is out-of-bounds
+   |
+note: inside `ptr::const_ptr::<impl *const u64>::offset`
+  --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
+   |
 LL |         unsafe { intrinsics::offset(self, count) }
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |                  |
-   |                  out-of-bounds pointer arithmetic: ALLOC_ID has size 8, so pointer to 8 bytes starting at offset 1 is out-of-bounds
-   |                  inside `ptr::const_ptr::<impl *const u64>::offset` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
-...
-LL |         unsafe { self.offset(count as isize) }
-   |                  --------------------------- inside `ptr::const_ptr::<impl *const u64>::add` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
+note: inside `ptr::const_ptr::<impl *const u64>::add`
+  --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
    |
-  ::: $DIR/forbidden_slices.rs:74:25
+LL |         unsafe { self.offset(count as isize) }
+   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+note: inside `R8`
+  --> $DIR/forbidden_slices.rs:74:25
    |
 LL |     from_ptr_range(ptr..ptr.add(1))
-   |                         ---------- inside `R8` at $DIR/forbidden_slices.rs:74:25
+   |                         ^^^^^^^^^^
 
 error[E0080]: could not evaluate static initializer
   --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
    |
 LL |         unsafe { intrinsics::ptr_offset_from_unsigned(self, origin) }
-   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |                  |
-   |                  `ptr_offset_from_unsigned` called on pointers into different allocations
-   |                  inside `ptr::const_ptr::<impl *const u32>::sub_ptr` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
+   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `ptr_offset_from_unsigned` called on pointers into different allocations
    |
-  ::: $SRC_DIR/core/src/slice/raw.rs:LL:COL
+note: inside `ptr::const_ptr::<impl *const u32>::sub_ptr`
+  --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
    |
-LL |     unsafe { from_raw_parts(range.start, range.end.sub_ptr(range.start)) }
-   |                                          ------------------------------ inside `from_ptr_range::<'_, u32>` at $SRC_DIR/core/src/slice/raw.rs:LL:COL
+LL |         unsafe { intrinsics::ptr_offset_from_unsigned(self, origin) }
+   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+note: inside `from_ptr_range::<'_, u32>`
+  --> $SRC_DIR/core/src/slice/raw.rs:LL:COL
    |
-  ::: $DIR/forbidden_slices.rs:79:34
+LL |     unsafe { from_raw_parts(range.start, range.end.sub_ptr(range.start)) }
+   |                                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+note: inside `R9`
+  --> $DIR/forbidden_slices.rs:79:34
    |
 LL | pub static R9: &[u32] = unsafe { from_ptr_range(&D0..(&D0 as *const u32).add(1)) };
-   |                                  ----------------------------------------------- inside `R9` at $DIR/forbidden_slices.rs:79:34
+   |                                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0080]: could not evaluate static initializer
   --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
    |
 LL |         unsafe { intrinsics::ptr_offset_from_unsigned(self, origin) }
-   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |                  |
-   |                  `ptr_offset_from_unsigned` called on pointers into different allocations
-   |                  inside `ptr::const_ptr::<impl *const u32>::sub_ptr` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
+   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `ptr_offset_from_unsigned` called on pointers into different allocations
    |
-  ::: $SRC_DIR/core/src/slice/raw.rs:LL:COL
+note: inside `ptr::const_ptr::<impl *const u32>::sub_ptr`
+  --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
    |
-LL |     unsafe { from_raw_parts(range.start, range.end.sub_ptr(range.start)) }
-   |                                          ------------------------------ inside `from_ptr_range::<'_, u32>` at $SRC_DIR/core/src/slice/raw.rs:LL:COL
+LL |         unsafe { intrinsics::ptr_offset_from_unsigned(self, origin) }
+   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+note: inside `from_ptr_range::<'_, u32>`
+  --> $SRC_DIR/core/src/slice/raw.rs:LL:COL
    |
-  ::: $DIR/forbidden_slices.rs:80:35
+LL |     unsafe { from_raw_parts(range.start, range.end.sub_ptr(range.start)) }
+   |                                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+note: inside `R10`
+  --> $DIR/forbidden_slices.rs:80:35
    |
 LL | pub static R10: &[u32] = unsafe { from_ptr_range(&D0..&D0) };
-   |                                   ------------------------ inside `R10` at $DIR/forbidden_slices.rs:80:35
+   |                                   ^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to 18 previous errors
 
index 52b173c4d04a8107dc522f71a8424386deb859db..bca29b4688136542bae551591938a27e90fa9de1 100644 (file)
@@ -2,53 +2,62 @@ error[E0080]: evaluation of constant value failed
   --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL
    |
 LL |         copy_nonoverlapping(src, tmp.as_mut_ptr(), 1);
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |         |
-   |         memory access failed: alloc5 has size 4, so pointer to 4 bytes starting at offset 4 is out-of-bounds
-   |         inside `std::ptr::read::<u32>` at $SRC_DIR/core/src/ptr/mod.rs:LL:COL
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: alloc5 has size 4, so pointer to 4 bytes starting at offset 4 is out-of-bounds
+   |
+note: inside `std::ptr::read::<u32>`
+  --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL
    |
-  ::: $DIR/out_of_bounds_read.rs:12:33
+LL |         copy_nonoverlapping(src, tmp.as_mut_ptr(), 1);
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+note: inside `_READ`
+  --> $DIR/out_of_bounds_read.rs:12:33
    |
 LL |     const _READ: u32 = unsafe { ptr::read(PAST_END_PTR) };
-   |                                 ----------------------- inside `_READ` at $DIR/out_of_bounds_read.rs:12:33
+   |                                 ^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0080]: evaluation of constant value failed
   --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL
    |
 LL |         copy_nonoverlapping(src, tmp.as_mut_ptr(), 1);
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |         |
-   |         memory access failed: alloc5 has size 4, so pointer to 4 bytes starting at offset 4 is out-of-bounds
-   |         inside `std::ptr::read::<u32>` at $SRC_DIR/core/src/ptr/mod.rs:LL:COL
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: alloc5 has size 4, so pointer to 4 bytes starting at offset 4 is out-of-bounds
    |
-  ::: $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
+note: inside `std::ptr::read::<u32>`
+  --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL
    |
-LL |         unsafe { read(self) }
-   |                  ---------- inside `ptr::const_ptr::<impl *const u32>::read` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
+LL |         copy_nonoverlapping(src, tmp.as_mut_ptr(), 1);
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+note: inside `ptr::const_ptr::<impl *const u32>::read`
+  --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
    |
-  ::: $DIR/out_of_bounds_read.rs:13:39
+LL |         unsafe { read(self) }
+   |                  ^^^^^^^^^^
+note: inside `_CONST_READ`
+  --> $DIR/out_of_bounds_read.rs:13:39
    |
 LL |     const _CONST_READ: u32 = unsafe { PAST_END_PTR.read() };
-   |                                       ------------------- inside `_CONST_READ` at $DIR/out_of_bounds_read.rs:13:39
+   |                                       ^^^^^^^^^^^^^^^^^^^
 
 error[E0080]: evaluation of constant value failed
   --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL
    |
 LL |         copy_nonoverlapping(src, tmp.as_mut_ptr(), 1);
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |         |
-   |         memory access failed: alloc5 has size 4, so pointer to 4 bytes starting at offset 4 is out-of-bounds
-   |         inside `std::ptr::read::<u32>` at $SRC_DIR/core/src/ptr/mod.rs:LL:COL
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: alloc5 has size 4, so pointer to 4 bytes starting at offset 4 is out-of-bounds
+   |
+note: inside `std::ptr::read::<u32>`
+  --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL
    |
-  ::: $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL
+LL |         copy_nonoverlapping(src, tmp.as_mut_ptr(), 1);
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+note: inside `ptr::mut_ptr::<impl *mut u32>::read`
+  --> $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL
    |
 LL |         unsafe { read(self) }
-   |                  ---------- inside `ptr::mut_ptr::<impl *mut u32>::read` at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL
-   |
-  ::: $DIR/out_of_bounds_read.rs:14:37
+   |                  ^^^^^^^^^^
+note: inside `_MUT_READ`
+  --> $DIR/out_of_bounds_read.rs:14:37
    |
 LL |     const _MUT_READ: u32 = unsafe { (PAST_END_PTR as *mut u32).read() };
-   |                                     --------------------------------- inside `_MUT_READ` at $DIR/out_of_bounds_read.rs:14:37
+   |                                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to 3 previous errors
 
index c685922c456b35be977d0b034f1976e9df376d92..f199170018f20b322a6971a8b21205052e6c5425 100644 (file)
@@ -12,15 +12,10 @@ LL |     = [0; (i8::MAX + 1u8) as usize];
    |
    = help: the trait `~const Add<u8>` is not implemented for `i8`
    = 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
+             <&i8 as Add<&i8>>
+             <i8 as Add<&i8>>
+             <i8 as Add>
 
 error: aborting due to 2 previous errors
 
index b396079240a98b2905fdfd6bab946381ede30b89..1f8e402317aa8d5bcb095bdbac13f453336137d5 100644 (file)
@@ -12,15 +12,10 @@ LL |     : [u32; (i8::MAX as i8 + 1u8) as usize]
    |
    = help: the trait `~const Add<u8>` is not implemented for `i8`
    = 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
+             <&i8 as Add<&i8>>
+             <i8 as Add<&i8>>
+             <i8 as Add>
 
 error[E0604]: only `u8` can be cast as `char`, not `i8`
   --> $DIR/const-eval-overflow-4b.rs:22:13
index 3784a3861c3deedc67a0c2346e1d5699d076e4ca..0734f479f9897b41a2190df93da3462fab41698e 100644 (file)
@@ -1,26 +1,36 @@
 error[E0080]: evaluation of constant value failed
   --> $DIR/const_fn_ptr_fail2.rs:9:5
    |
+LL |     x(y)
+   |     ^^^^ calling non-const function `double`
+   |
+note: inside `bar`
+  --> $DIR/const_fn_ptr_fail2.rs:9:5
+   |
 LL |     x(y)
    |     ^^^^
-   |     |
-   |     calling non-const function `double`
-   |     inside `bar` at $DIR/const_fn_ptr_fail2.rs:9:5
-...
+note: inside `Y`
+  --> $DIR/const_fn_ptr_fail2.rs:14:18
+   |
 LL | const Y: usize = bar(X, 2); // FIXME: should fail to typeck someday
-   |                  --------- inside `Y` at $DIR/const_fn_ptr_fail2.rs:14:18
+   |                  ^^^^^^^^^
 
 error[E0080]: evaluation of constant value failed
   --> $DIR/const_fn_ptr_fail2.rs:9:5
    |
+LL |     x(y)
+   |     ^^^^ calling non-const function `double`
+   |
+note: inside `bar`
+  --> $DIR/const_fn_ptr_fail2.rs:9:5
+   |
 LL |     x(y)
    |     ^^^^
-   |     |
-   |     calling non-const function `double`
-   |     inside `bar` at $DIR/const_fn_ptr_fail2.rs:9:5
-...
+note: inside `Z`
+  --> $DIR/const_fn_ptr_fail2.rs:15:18
+   |
 LL | const Z: usize = bar(double, 2); // FIXME: should fail to typeck someday
-   |                  -------------- inside `Z` at $DIR/const_fn_ptr_fail2.rs:15:18
+   |                  ^^^^^^^^^^^^^^
 
 warning: skipping const checks
    |
index 5c3b412d37fcc1752520abd7df779648c8e14705..846458176d6fd79fc1fb710ace41c55912adc867 100644 (file)
@@ -1,14 +1,19 @@
 error[E0080]: evaluation of constant value failed
   --> $DIR/const_panic_track_caller.rs:15:5
    |
+LL |     b()
+   |     ^^^ the evaluated program panicked at 'hey', $DIR/const_panic_track_caller.rs:15:5
+   |
+note: inside `c`
+  --> $DIR/const_panic_track_caller.rs:15:5
+   |
 LL |     b()
    |     ^^^
-   |     |
-   |     the evaluated program panicked at 'hey', $DIR/const_panic_track_caller.rs:15:5
-   |     inside `c` at $DIR/const_panic_track_caller.rs:15:5
-...
+note: inside `X`
+  --> $DIR/const_panic_track_caller.rs:21:16
+   |
 LL | const X: u32 = c();
-   |                --- inside `X` at $DIR/const_panic_track_caller.rs:21:16
+   |                ^^^
 
 error: aborting due to previous error
 
index 2628a78455c76b3f5a5f3100852c11807ecb8a26..8f3b3d5f700a22c037f5519126495dd722befa7d 100644 (file)
@@ -1,14 +1,19 @@
 error[E0080]: evaluation of constant value failed
   --> $DIR/alloc_intrinsic_errors.rs:9:17
    |
-LL | const FOO: i32 = foo();
-   |                  ----- inside `FOO` at $DIR/alloc_intrinsic_errors.rs:6:18
-...
+LL |         let _ = intrinsics::const_allocate(4, 3) as *mut i32;
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ align has to be a power of 2, `3` is not a power of 2
+   |
+note: inside `foo`
+  --> $DIR/alloc_intrinsic_errors.rs:9:17
+   |
 LL |         let _ = intrinsics::const_allocate(4, 3) as *mut i32;
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |                 |
-   |                 align has to be a power of 2, `3` is not a power of 2
-   |                 inside `foo` at $DIR/alloc_intrinsic_errors.rs:9:17
+note: inside `FOO`
+  --> $DIR/alloc_intrinsic_errors.rs:6:18
+   |
+LL | const FOO: i32 = foo();
+   |                  ^^^^^
 
 error: aborting due to previous error
 
index 99178ae8c83d1bddfbcc430d905cd158aee4552a..759ce15ab1b5d30e74961ac7077802d0f0d8317e 100644 (file)
@@ -1,15 +1,19 @@
 error[E0080]: evaluation of constant value failed
   --> $DIR/unwind-abort.rs:4:5
    |
+LL |     panic!()
+   |     ^^^^^^^^ the evaluated program panicked at 'explicit panic', $DIR/unwind-abort.rs:4:5
+   |
+note: inside `foo`
+  --> $DIR/unwind-abort.rs:4:5
+   |
 LL |     panic!()
    |     ^^^^^^^^
-   |     |
-   |     the evaluated program panicked at 'explicit panic', $DIR/unwind-abort.rs:4:5
-   |     inside `foo` at $SRC_DIR/std/src/panic.rs:LL:COL
-...
-LL | const _: () = foo();
-   |               ----- inside `_` at $DIR/unwind-abort.rs:7:15
+note: inside `_`
+  --> $DIR/unwind-abort.rs:7:15
    |
+LL | const _: () = foo();
+   |               ^^^^^
    = note: this error originates in the macro `$crate::panic::panic_2015` which comes from the expansion of the macro `panic` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: aborting due to previous error
index 8b4d845b30eaa0ee857d6614645a4e6bee00cf8f..9710bf476ecc913b26808998c73240d9bad37f3f 100644 (file)
@@ -13,14 +13,19 @@ LL |     unsafe { std::mem::transmute(()) }
 error[E0080]: evaluation of constant value failed
   --> $DIR/validate_uninhabited_zsts.rs:4:14
    |
+LL |     unsafe { std::mem::transmute(()) }
+   |              ^^^^^^^^^^^^^^^^^^^^^^^ transmuting to uninhabited type
+   |
+note: inside `foo`
+  --> $DIR/validate_uninhabited_zsts.rs:4:14
+   |
 LL |     unsafe { std::mem::transmute(()) }
    |              ^^^^^^^^^^^^^^^^^^^^^^^
-   |              |
-   |              transmuting to uninhabited type
-   |              inside `foo` at $DIR/validate_uninhabited_zsts.rs:4:14
-...
+note: inside `FOO`
+  --> $DIR/validate_uninhabited_zsts.rs:19:33
+   |
 LL | const FOO: [empty::Empty; 3] = [foo(); 3];
-   |                                 ----- inside `FOO` at $DIR/validate_uninhabited_zsts.rs:19:33
+   |                                 ^^^^^
 
 error[E0080]: it is undefined behavior to use this value
   --> $DIR/validate_uninhabited_zsts.rs:21:1
index 8b4d845b30eaa0ee857d6614645a4e6bee00cf8f..9710bf476ecc913b26808998c73240d9bad37f3f 100644 (file)
@@ -13,14 +13,19 @@ LL |     unsafe { std::mem::transmute(()) }
 error[E0080]: evaluation of constant value failed
   --> $DIR/validate_uninhabited_zsts.rs:4:14
    |
+LL |     unsafe { std::mem::transmute(()) }
+   |              ^^^^^^^^^^^^^^^^^^^^^^^ transmuting to uninhabited type
+   |
+note: inside `foo`
+  --> $DIR/validate_uninhabited_zsts.rs:4:14
+   |
 LL |     unsafe { std::mem::transmute(()) }
    |              ^^^^^^^^^^^^^^^^^^^^^^^
-   |              |
-   |              transmuting to uninhabited type
-   |              inside `foo` at $DIR/validate_uninhabited_zsts.rs:4:14
-...
+note: inside `FOO`
+  --> $DIR/validate_uninhabited_zsts.rs:19:33
+   |
 LL | const FOO: [empty::Empty; 3] = [foo(); 3];
-   |                                 ----- inside `FOO` at $DIR/validate_uninhabited_zsts.rs:19:33
+   |                                 ^^^^^
 
 error[E0080]: it is undefined behavior to use this value
   --> $DIR/validate_uninhabited_zsts.rs:21:1
index e1ad72416f264f02496400b43fa1caf19ad6be50..195a087ffa5b0aad0c0c8abd0e41b7885cf29fd2 100644 (file)
@@ -1,39 +1,47 @@
 error[E0080]: evaluation of constant value failed
   --> $SRC_DIR/core/src/num/f32.rs:LL:COL
    |
+LL |                     panic!("const-eval error: cannot use f32::to_bits on a NaN")
+   |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'const-eval error: cannot use f32::to_bits on a NaN', $SRC_DIR/core/src/num/f32.rs:LL:COL
+   |
+note: inside `core::f32::<impl f32>::to_bits::ct_f32_to_u32`
+  --> $SRC_DIR/core/src/num/f32.rs:LL:COL
+   |
 LL |                     panic!("const-eval error: cannot use f32::to_bits on a NaN")
    |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |                     |
-   |                     the evaluated program panicked at 'const-eval error: cannot use f32::to_bits on a NaN', $SRC_DIR/core/src/num/f32.rs:LL:COL
-   |                     inside `core::f32::<impl f32>::to_bits::ct_f32_to_u32` at $SRC_DIR/core/src/panic.rs:LL:COL
-...
-LL |         unsafe { intrinsics::const_eval_select((self,), ct_f32_to_u32, rt_f32_to_u32) }
-   |                  -------------------------------------------------------------------- inside `core::f32::<impl f32>::to_bits` at $SRC_DIR/core/src/num/f32.rs:LL:COL
+note: inside `core::f32::<impl f32>::to_bits`
+  --> $SRC_DIR/core/src/num/f32.rs:LL:COL
    |
-  ::: $DIR/const-float-bits-reject-conv.rs:28:30
+LL |         unsafe { intrinsics::const_eval_select((self,), ct_f32_to_u32, rt_f32_to_u32) }
+   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+note: inside `f32::MASKED_NAN1`
+  --> $DIR/const-float-bits-reject-conv.rs:28:30
    |
 LL |     const MASKED_NAN1: u32 = f32::NAN.to_bits() ^ 0x002A_AAAA;
-   |                              ------------------ inside `f32::MASKED_NAN1` at $DIR/const-float-bits-reject-conv.rs:28:30
-   |
+   |                              ^^^^^^^^^^^^^^^^^^
    = note: this error originates in the macro `$crate::panic::panic_2021` which comes from the expansion of the macro `panic` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error[E0080]: evaluation of constant value failed
   --> $SRC_DIR/core/src/num/f32.rs:LL:COL
    |
+LL |                     panic!("const-eval error: cannot use f32::to_bits on a NaN")
+   |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'const-eval error: cannot use f32::to_bits on a NaN', $SRC_DIR/core/src/num/f32.rs:LL:COL
+   |
+note: inside `core::f32::<impl f32>::to_bits::ct_f32_to_u32`
+  --> $SRC_DIR/core/src/num/f32.rs:LL:COL
+   |
 LL |                     panic!("const-eval error: cannot use f32::to_bits on a NaN")
    |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |                     |
-   |                     the evaluated program panicked at 'const-eval error: cannot use f32::to_bits on a NaN', $SRC_DIR/core/src/num/f32.rs:LL:COL
-   |                     inside `core::f32::<impl f32>::to_bits::ct_f32_to_u32` at $SRC_DIR/core/src/panic.rs:LL:COL
-...
-LL |         unsafe { intrinsics::const_eval_select((self,), ct_f32_to_u32, rt_f32_to_u32) }
-   |                  -------------------------------------------------------------------- inside `core::f32::<impl f32>::to_bits` at $SRC_DIR/core/src/num/f32.rs:LL:COL
+note: inside `core::f32::<impl f32>::to_bits`
+  --> $SRC_DIR/core/src/num/f32.rs:LL:COL
    |
-  ::: $DIR/const-float-bits-reject-conv.rs:30:30
+LL |         unsafe { intrinsics::const_eval_select((self,), ct_f32_to_u32, rt_f32_to_u32) }
+   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+note: inside `f32::MASKED_NAN2`
+  --> $DIR/const-float-bits-reject-conv.rs:30:30
    |
 LL |     const MASKED_NAN2: u32 = f32::NAN.to_bits() ^ 0x0055_5555;
-   |                              ------------------ inside `f32::MASKED_NAN2` at $DIR/const-float-bits-reject-conv.rs:30:30
-   |
+   |                              ^^^^^^^^^^^^^^^^^^
    = note: this error originates in the macro `$crate::panic::panic_2021` which comes from the expansion of the macro `panic` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 note: erroneous constant used
@@ -63,39 +71,47 @@ LL |     const_assert!(f32::from_bits(MASKED_NAN2).to_bits(), MASKED_NAN2);
 error[E0080]: evaluation of constant value failed
   --> $SRC_DIR/core/src/num/f64.rs:LL:COL
    |
+LL |                     panic!("const-eval error: cannot use f64::to_bits on a NaN")
+   |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'const-eval error: cannot use f64::to_bits on a NaN', $SRC_DIR/core/src/num/f64.rs:LL:COL
+   |
+note: inside `core::f64::<impl f64>::to_bits::ct_f64_to_u64`
+  --> $SRC_DIR/core/src/num/f64.rs:LL:COL
+   |
 LL |                     panic!("const-eval error: cannot use f64::to_bits on a NaN")
    |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |                     |
-   |                     the evaluated program panicked at 'const-eval error: cannot use f64::to_bits on a NaN', $SRC_DIR/core/src/num/f64.rs:LL:COL
-   |                     inside `core::f64::<impl f64>::to_bits::ct_f64_to_u64` at $SRC_DIR/core/src/panic.rs:LL:COL
-...
-LL |         unsafe { intrinsics::const_eval_select((self,), ct_f64_to_u64, rt_f64_to_u64) }
-   |                  -------------------------------------------------------------------- inside `core::f64::<impl f64>::to_bits` at $SRC_DIR/core/src/num/f64.rs:LL:COL
+note: inside `core::f64::<impl f64>::to_bits`
+  --> $SRC_DIR/core/src/num/f64.rs:LL:COL
    |
-  ::: $DIR/const-float-bits-reject-conv.rs:50:30
+LL |         unsafe { intrinsics::const_eval_select((self,), ct_f64_to_u64, rt_f64_to_u64) }
+   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+note: inside `f64::MASKED_NAN1`
+  --> $DIR/const-float-bits-reject-conv.rs:50:30
    |
 LL |     const MASKED_NAN1: u64 = f64::NAN.to_bits() ^ 0x000A_AAAA_AAAA_AAAA;
-   |                              ------------------ inside `f64::MASKED_NAN1` at $DIR/const-float-bits-reject-conv.rs:50:30
-   |
+   |                              ^^^^^^^^^^^^^^^^^^
    = note: this error originates in the macro `$crate::panic::panic_2021` which comes from the expansion of the macro `panic` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error[E0080]: evaluation of constant value failed
   --> $SRC_DIR/core/src/num/f64.rs:LL:COL
    |
+LL |                     panic!("const-eval error: cannot use f64::to_bits on a NaN")
+   |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'const-eval error: cannot use f64::to_bits on a NaN', $SRC_DIR/core/src/num/f64.rs:LL:COL
+   |
+note: inside `core::f64::<impl f64>::to_bits::ct_f64_to_u64`
+  --> $SRC_DIR/core/src/num/f64.rs:LL:COL
+   |
 LL |                     panic!("const-eval error: cannot use f64::to_bits on a NaN")
    |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |                     |
-   |                     the evaluated program panicked at 'const-eval error: cannot use f64::to_bits on a NaN', $SRC_DIR/core/src/num/f64.rs:LL:COL
-   |                     inside `core::f64::<impl f64>::to_bits::ct_f64_to_u64` at $SRC_DIR/core/src/panic.rs:LL:COL
-...
-LL |         unsafe { intrinsics::const_eval_select((self,), ct_f64_to_u64, rt_f64_to_u64) }
-   |                  -------------------------------------------------------------------- inside `core::f64::<impl f64>::to_bits` at $SRC_DIR/core/src/num/f64.rs:LL:COL
+note: inside `core::f64::<impl f64>::to_bits`
+  --> $SRC_DIR/core/src/num/f64.rs:LL:COL
    |
-  ::: $DIR/const-float-bits-reject-conv.rs:52:30
+LL |         unsafe { intrinsics::const_eval_select((self,), ct_f64_to_u64, rt_f64_to_u64) }
+   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+note: inside `f64::MASKED_NAN2`
+  --> $DIR/const-float-bits-reject-conv.rs:52:30
    |
 LL |     const MASKED_NAN2: u64 = f64::NAN.to_bits() ^ 0x0005_5555_5555_5555;
-   |                              ------------------ inside `f64::MASKED_NAN2` at $DIR/const-float-bits-reject-conv.rs:52:30
-   |
+   |                              ^^^^^^^^^^^^^^^^^^
    = note: this error originates in the macro `$crate::panic::panic_2021` which comes from the expansion of the macro `panic` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 note: erroneous constant used
index 234e55e3a96c8beb7e5cb0cd84e332fa35ceeade..6e110dbdd6417dd5f87e0f8e845437e592dd6d6f 100644 (file)
@@ -1,14 +1,19 @@
 error[E0080]: evaluation of constant value failed
   --> $DIR/mut_ref_in_final_dynamic_check.rs:13:10
    |
+LL |     Some(&mut *(42 as *mut i32))
+   |          ^^^^^^^^^^^^^^^^^^^^^^ dereferencing pointer failed: 0x2a[noalloc] is a dangling pointer (it has no provenance)
+   |
+note: inside `helper`
+  --> $DIR/mut_ref_in_final_dynamic_check.rs:13:10
+   |
 LL |     Some(&mut *(42 as *mut i32))
    |          ^^^^^^^^^^^^^^^^^^^^^^
-   |          |
-   |          dereferencing pointer failed: 0x2a[noalloc] is a dangling pointer (it has no provenance)
-   |          inside `helper` at $DIR/mut_ref_in_final_dynamic_check.rs:13:10
-...
+note: inside `A`
+  --> $DIR/mut_ref_in_final_dynamic_check.rs:18:29
+   |
 LL | const A: Option<&mut i32> = helper();
-   |                             -------- inside `A` at $DIR/mut_ref_in_final_dynamic_check.rs:18:29
+   |                             ^^^^^^^^
 
 error: encountered dangling pointer in final constant
   --> $DIR/mut_ref_in_final_dynamic_check.rs:25:1
index 5093fe5391547d3650b952348a2537a426a51a83..1f56f581c0270b827627b9329f84d27c9d1ae719 100644 (file)
@@ -45,7 +45,7 @@ enum CLike { One = 1, #[allow(dead_code)] Two = 2, }
     const TUPLE: (OND, OND) = (None, None);
     match (None, None) { TUPLE => dbg!(TUPLE), _ => panic!("whoops"), };
 
-    const TYPE_ASCRIPTION: OND = None: OND;
+    const TYPE_ASCRIPTION: OND = type_ascribe!(None, OND);
     match None { TYPE_ASCRIPTION => dbg!(TYPE_ASCRIPTION), _ => panic!("whoops"), };
 
     const ARRAY: [OND; 2] = [None, None];
index 7a8169bec45beadbcd6d6ed6ab72b61f87055ceb..75fde0d92de17d729a9681bab9d9816020a1cd5c 100644 (file)
@@ -53,7 +53,7 @@ enum Derive<X> { Some(X), None, }
     match (None, Some(NoDerive)) { TUPLE => dbg!(TUPLE), _ => panic!("whoops"), };
     //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]`
 
-    const TYPE_ASCRIPTION: OND = Some(NoDerive): OND;
+    const TYPE_ASCRIPTION: OND = type_ascribe!(Some(NoDerive), OND);
     match Some(NoDerive) { TYPE_ASCRIPTION => dbg!(TYPE_ASCRIPTION), _ => panic!("whoops"), };
     //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]`
 
index f6de3699f778189891594022be12634cd343def9..cbc7cac937ae1b5b945e34a8c4f411780f26bd70 100644 (file)
@@ -2,18 +2,23 @@ error[E0080]: evaluation of constant value failed
   --> $SRC_DIR/core/src/hint.rs:LL:COL
    |
 LL |         intrinsics::unreachable()
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^
-   |         |
-   |         entering unreachable code
-   |         inside `unreachable_unchecked` at $SRC_DIR/core/src/hint.rs:LL:COL
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^ entering unreachable code
+   |
+note: inside `unreachable_unchecked`
+  --> $SRC_DIR/core/src/hint.rs:LL:COL
    |
-  ::: $DIR/const_unsafe_unreachable_ub.rs:6:18
+LL |         intrinsics::unreachable()
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^
+note: inside `foo`
+  --> $DIR/const_unsafe_unreachable_ub.rs:6:18
    |
 LL |         false => std::hint::unreachable_unchecked(),
-   |                  ---------------------------------- inside `foo` at $DIR/const_unsafe_unreachable_ub.rs:6:18
-...
+   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+note: inside `BAR`
+  --> $DIR/const_unsafe_unreachable_ub.rs:10:28
+   |
 LL | const BAR: bool = unsafe { foo(false) };
-   |                            ---------- inside `BAR` at $DIR/const_unsafe_unreachable_ub.rs:10:28
+   |                            ^^^^^^^^^^
 
 error: aborting due to previous error
 
index 4726905ade341e5d42d5daac35cbbda59ca49fef..2603a73583ebda4b6b007a9668a8ece944b3c545 100644 (file)
@@ -32,20 +32,23 @@ error[E0080]: evaluation of constant value failed
   --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL
    |
 LL |         copy_nonoverlapping(src, tmp.as_mut_ptr(), 1);
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |         |
-   |         accessing memory with alignment 1, but alignment 4 is required
-   |         inside `std::ptr::read::<u32>` at $SRC_DIR/core/src/ptr/mod.rs:LL:COL
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ accessing memory with alignment 1, but alignment 4 is required
    |
-  ::: $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
+note: inside `std::ptr::read::<u32>`
+  --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL
    |
-LL |         unsafe { read(self) }
-   |                  ---------- inside `ptr::const_ptr::<impl *const u32>::read` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
+LL |         copy_nonoverlapping(src, tmp.as_mut_ptr(), 1);
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+note: inside `ptr::const_ptr::<impl *const u32>::read`
+  --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
    |
-  ::: $DIR/detect-extra-ub.rs:38:9
+LL |         unsafe { read(self) }
+   |                  ^^^^^^^^^^
+note: inside `INNER`
+  --> $DIR/detect-extra-ub.rs:38:9
    |
 LL |         ptr.read();
-   |         ---------- inside `INNER` at $DIR/detect-extra-ub.rs:38:9
+   |         ^^^^^^^^^^
 
 note: erroneous constant used
   --> $DIR/detect-extra-ub.rs:32:5
index 3872e3d4f0decb2cdd1d4ca13e09d390a90ff7ab..1f82e1777af5bf43de2242ccd75029923cf5fc71 100644 (file)
@@ -2,23 +2,25 @@ error[E0080]: evaluation of constant value failed
   --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL
    |
 LL |         copy_nonoverlapping(src, tmp.as_mut_ptr(), 1);
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |         |
-   |         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
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to copy parts of a pointer from memory at ALLOC
    |
-  ::: $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
+   = 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: inside `std::ptr::read::<u8>`
+  --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL
    |
-LL |         unsafe { read(self) }
-   |                  ---------- inside `ptr::const_ptr::<impl *const u8>::read` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
+LL |         copy_nonoverlapping(src, tmp.as_mut_ptr(), 1);
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+note: inside `ptr::const_ptr::<impl *const u8>::read`
+  --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
    |
-  ::: $DIR/issue-miri-1910.rs:8:5
+LL |         unsafe { read(self) }
+   |                  ^^^^^^^^^^
+note: inside `C`
+  --> $DIR/issue-miri-1910.rs:8:5
    |
 LL |     (&foo as *const _ as *const u8).add(one_and_a_half_pointers).read();
-   |     ------------------------------------------------------------------- inside `C` at $DIR/issue-miri-1910.rs:8:5
-   |
-   = 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
 
index 840d698ebbfaf7b044ee486e2332a324010daede..cf3fd88d0342e06c15700d8e46ea2ad669b4add0 100644 (file)
@@ -1,14 +1,19 @@
 error[E0080]: could not evaluate static initializer
   --> $DIR/abi-mismatch.rs:9:5
    |
+LL |     my_fn();
+   |     ^^^^^^^ calling a function with calling convention C using calling convention Rust
+   |
+note: inside `call_rust_fn`
+  --> $DIR/abi-mismatch.rs:9:5
+   |
 LL |     my_fn();
    |     ^^^^^^^
-   |     |
-   |     calling a function with calling convention C using calling convention Rust
-   |     inside `call_rust_fn` at $DIR/abi-mismatch.rs:9:5
-...
+note: inside `VAL`
+  --> $DIR/abi-mismatch.rs:15:18
+   |
 LL | static VAL: () = call_rust_fn(unsafe { std::mem::transmute(c_fn as extern "C" fn()) });
-   |                  --------------------------------------------------------------------- inside `VAL` at $DIR/abi-mismatch.rs:15:18
+   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: skipping const checks
    |
index 33e7e4af276f7418cfb443c530f9a312d37fa828..b26f121dba0612946658cb27fc97dbf5dddaa642 100644 (file)
@@ -1,17 +1,24 @@
 error[E0080]: evaluation of `<std::string::String as Bar<std::vec::Vec<u32>, std::string::String>>::F` failed
   --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL
    |
+LL | pub unsafe fn drop_in_place<T: ?Sized>(to_drop: *mut T) {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ calling non-const function `<Vec<u32> as Drop>::drop`
+   |
+note: inside `std::ptr::drop_in_place::<Vec<u32>> - shim(Some(Vec<u32>))`
+  --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL
+   |
 LL | pub unsafe fn drop_in_place<T: ?Sized>(to_drop: *mut T) {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   | |
-   | calling non-const function `<Vec<u32> as Drop>::drop`
-   | inside `std::ptr::drop_in_place::<Vec<u32>> - shim(Some(Vec<u32>))` at $SRC_DIR/core/src/ptr/mod.rs:LL:COL
-   | inside `std::ptr::drop_in_place::<(Vec<u32>, u32)> - shim(Some((Vec<u32>, u32)))` at $SRC_DIR/core/src/ptr/mod.rs:LL:COL
+note: inside `std::ptr::drop_in_place::<(Vec<u32>, u32)> - shim(Some((Vec<u32>, u32)))`
+  --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL
    |
-  ::: $DIR/assoc_const.rs:12:31
+LL | pub unsafe fn drop_in_place<T: ?Sized>(to_drop: *mut T) {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+note: inside `<String as Bar<Vec<u32>, String>>::F`
+  --> $DIR/assoc_const.rs:12:31
    |
 LL |     const F: u32 = (U::X, 42).1;
-   |                               - inside `<String as Bar<Vec<u32>, String>>::F` at $DIR/assoc_const.rs:12:31
+   |                               ^
 
 note: erroneous constant used
   --> $DIR/assoc_const.rs:29:13
index a3a502723d223d1399ad88dbe4f089eda6c4b99d..e2e2f16d5a02500fc5d03ffd14412dc9e2be89ef 100644 (file)
@@ -2,15 +2,18 @@ error[E0080]: could not evaluate static initializer
   --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL
    |
 LL | pub unsafe fn drop_in_place<T: ?Sized>(to_drop: *mut T) {
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   | |
-   | calling non-const function `<Vec<i32> as Drop>::drop`
-   | inside `std::ptr::drop_in_place::<Vec<i32>> - shim(Some(Vec<i32>))` at $SRC_DIR/core/src/ptr/mod.rs:LL:COL
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ calling non-const function `<Vec<i32> as Drop>::drop`
+   |
+note: inside `std::ptr::drop_in_place::<Vec<i32>> - shim(Some(Vec<i32>))`
+  --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL
    |
-  ::: $DIR/drop.rs:17:1
+LL | pub unsafe fn drop_in_place<T: ?Sized>(to_drop: *mut T) {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+note: inside `TEST_BAD`
+  --> $DIR/drop.rs:17:1
    |
 LL | };
-   | - inside `TEST_BAD` at $DIR/drop.rs:17:1
+   | ^
 
 warning: skipping const checks
    |
index 436c5112360e738dd5f80449d7a3a8afcf9ecc3c..7aaeadd0403cbe5e36115c26eb38cb7fa3b47f8c 100644 (file)
@@ -2,13 +2,13 @@ error[E0080]: could not evaluate static initializer
   --> $DIR/tls.rs:11:25
    |
 LL |     unsafe { let _val = A; }
-   |                         ^ cannot access thread local static (DefId(0:6 ~ tls[78b0]::A))
+   |                         ^ cannot access thread local static (DefId(0:4 ~ tls[78b0]::A))
 
 error[E0080]: could not evaluate static initializer
   --> $DIR/tls.rs:18:26
    |
 LL |     unsafe { let _val = &A; }
-   |                          ^ cannot access thread local static (DefId(0:6 ~ tls[78b0]::A))
+   |                          ^ cannot access thread local static (DefId(0:4 ~ tls[78b0]::A))
 
 warning: skipping const checks
    |
diff --git a/src/test/ui/consts/missing_span_in_backtrace.rs b/src/test/ui/consts/missing_span_in_backtrace.rs
new file mode 100644 (file)
index 0000000..c4930b7
--- /dev/null
@@ -0,0 +1,27 @@
+// compile-flags: -Z simulate-remapped-rust-src-base=/rustc/FAKE_PREFIX -Z translate-remapped-path-to-local-path=no -Z ui-testing=no
+// normalize-stderr-test "alloc[0-9]+" -> "ALLOC_ID"
+
+#![feature(const_swap)]
+#![feature(const_mut_refs)]
+use std::{
+    mem::{self, MaybeUninit},
+    ptr,
+};
+
+const X: () = {
+    let mut ptr1 = &1;
+    let mut ptr2 = &2;
+
+    // Swap them, bytewise.
+    unsafe {
+        ptr::swap_nonoverlapping(
+            &mut ptr1 as *mut _ as *mut MaybeUninit<u8>,
+            &mut ptr2 as *mut _ as *mut MaybeUninit<u8>,
+            mem::size_of::<&i32>(),
+        );
+    }
+};
+
+fn main() {
+    X
+}
diff --git a/src/test/ui/consts/missing_span_in_backtrace.stderr b/src/test/ui/consts/missing_span_in_backtrace.stderr
new file mode 100644 (file)
index 0000000..e6d3d51
--- /dev/null
@@ -0,0 +1,28 @@
+error[E0080]: evaluation of constant value failed
+  --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL
+   |
+   = note: unable to copy parts of a pointer from memory at ALLOC_ID
+   |
+   = 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: inside `std::ptr::read::<MaybeUninit<MaybeUninit<u8>>>`
+  --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL
+note: inside `mem::swap_simple::<MaybeUninit<MaybeUninit<u8>>>`
+  --> $SRC_DIR/core/src/mem/mod.rs:LL:COL
+note: inside `ptr::swap_nonoverlapping_simple_untyped::<MaybeUninit<u8>>`
+  --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL
+note: inside `swap_nonoverlapping::<MaybeUninit<u8>>`
+  --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL
+note: inside `X`
+  --> $DIR/missing_span_in_backtrace.rs:17:9
+   |
+17 | /         ptr::swap_nonoverlapping(
+18 | |             &mut ptr1 as *mut _ as *mut MaybeUninit<u8>,
+19 | |             &mut ptr2 as *mut _ as *mut MaybeUninit<u8>,
+20 | |             mem::size_of::<&i32>(),
+21 | |         );
+   | |_________^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0080`.
index 62a087d94d3565894d4043cff00b66526097b54b..9578d90ea9d8827762177a1be47df1d3a080745a 100644 (file)
@@ -8,15 +8,18 @@ error[E0080]: evaluation of constant value failed
   --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
    |
 LL |         unsafe { intrinsics::ptr_offset_from(self, origin) }
-   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |                  |
-   |                  `ptr_offset_from` called on pointers into different allocations
-   |                  inside `ptr::const_ptr::<impl *const u8>::offset_from` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
+   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `ptr_offset_from` called on pointers into different allocations
+   |
+note: inside `ptr::const_ptr::<impl *const u8>::offset_from`
+  --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
    |
-  ::: $DIR/offset_from_ub.rs:24:14
+LL |         unsafe { intrinsics::ptr_offset_from(self, origin) }
+   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+note: inside `NOT_PTR`
+  --> $DIR/offset_from_ub.rs:24:14
    |
 LL |     unsafe { (42 as *const u8).offset_from(&5u8) as usize }
-   |              ----------------------------------- inside `NOT_PTR` at $DIR/offset_from_ub.rs:24:14
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0080]: evaluation of constant value failed
   --> $DIR/offset_from_ub.rs:31:14
@@ -88,29 +91,35 @@ error[E0080]: evaluation of constant value failed
   --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
    |
 LL |         unsafe { intrinsics::ptr_offset_from(self, origin) }
-   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |                  |
-   |                  out-of-bounds offset_from: null pointer is a dangling pointer (it has no provenance)
-   |                  inside `ptr::const_ptr::<impl *const u8>::offset_from` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
+   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds offset_from: null pointer is a dangling pointer (it has no provenance)
    |
-  ::: $DIR/offset_from_ub.rs:115:14
+note: inside `ptr::const_ptr::<impl *const u8>::offset_from`
+  --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
+   |
+LL |         unsafe { intrinsics::ptr_offset_from(self, origin) }
+   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+note: inside `OFFSET_VERY_FAR1`
+  --> $DIR/offset_from_ub.rs:115:14
    |
 LL |     unsafe { ptr2.offset_from(ptr1) }
-   |              ---------------------- inside `OFFSET_VERY_FAR1` at $DIR/offset_from_ub.rs:115:14
+   |              ^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0080]: evaluation of constant value failed
   --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
    |
 LL |         unsafe { intrinsics::ptr_offset_from(self, origin) }
-   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |                  |
-   |                  out-of-bounds offset_from: null pointer is a dangling pointer (it has no provenance)
-   |                  inside `ptr::const_ptr::<impl *const u8>::offset_from` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
+   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds offset_from: null pointer is a dangling pointer (it has no provenance)
    |
-  ::: $DIR/offset_from_ub.rs:121:14
+note: inside `ptr::const_ptr::<impl *const u8>::offset_from`
+  --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
+   |
+LL |         unsafe { intrinsics::ptr_offset_from(self, origin) }
+   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+note: inside `OFFSET_VERY_FAR2`
+  --> $DIR/offset_from_ub.rs:121:14
    |
 LL |     unsafe { ptr1.offset_from(ptr2.wrapping_offset(1)) }
-   |              ----------------------------------------- inside `OFFSET_VERY_FAR2` at $DIR/offset_from_ub.rs:121:14
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to 15 previous errors
 
index 5a792bba50cb2ecb20e42fd29a21f248a09f8784..7938f70a2695ed60f43b0123a4177340da9b5902 100644 (file)
@@ -2,169 +2,205 @@ error[E0080]: evaluation of constant value failed
   --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
    |
 LL |         unsafe { intrinsics::offset(self, count) }
-   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |                  |
-   |                  overflowing in-bounds pointer arithmetic
-   |                  inside `ptr::const_ptr::<impl *const u8>::offset` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
+   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflowing in-bounds pointer arithmetic
+   |
+note: inside `ptr::const_ptr::<impl *const u8>::offset`
+  --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
    |
-  ::: $DIR/offset_ub.rs:7:46
+LL |         unsafe { intrinsics::offset(self, count) }
+   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+note: inside `BEFORE_START`
+  --> $DIR/offset_ub.rs:7:46
    |
 LL | pub const BEFORE_START: *const u8 = unsafe { (&0u8 as *const u8).offset(-1) };
-   |                                              ------------------------------ inside `BEFORE_START` at $DIR/offset_ub.rs:7:46
+   |                                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0080]: evaluation of constant value failed
   --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
    |
 LL |         unsafe { intrinsics::offset(self, count) }
-   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |                  |
-   |                  out-of-bounds pointer arithmetic: allocN has size 1, so pointer to 2 bytes starting at offset 0 is out-of-bounds
-   |                  inside `ptr::const_ptr::<impl *const u8>::offset` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
+   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer arithmetic: allocN has size 1, so pointer to 2 bytes starting at offset 0 is out-of-bounds
    |
-  ::: $DIR/offset_ub.rs:8:43
+note: inside `ptr::const_ptr::<impl *const u8>::offset`
+  --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
+   |
+LL |         unsafe { intrinsics::offset(self, count) }
+   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+note: inside `AFTER_END`
+  --> $DIR/offset_ub.rs:8:43
    |
 LL | pub const AFTER_END: *const u8 = unsafe { (&0u8 as *const u8).offset(2) };
-   |                                           ----------------------------- inside `AFTER_END` at $DIR/offset_ub.rs:8:43
+   |                                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0080]: evaluation of constant value failed
   --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
    |
 LL |         unsafe { intrinsics::offset(self, count) }
-   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |                  |
-   |                  out-of-bounds pointer arithmetic: allocN has size 100, so pointer to 101 bytes starting at offset 0 is out-of-bounds
-   |                  inside `ptr::const_ptr::<impl *const u8>::offset` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
+   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer arithmetic: allocN has size 100, so pointer to 101 bytes starting at offset 0 is out-of-bounds
    |
-  ::: $DIR/offset_ub.rs:9:45
+note: inside `ptr::const_ptr::<impl *const u8>::offset`
+  --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
+   |
+LL |         unsafe { intrinsics::offset(self, count) }
+   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+note: inside `AFTER_ARRAY`
+  --> $DIR/offset_ub.rs:9:45
    |
 LL | pub const AFTER_ARRAY: *const u8 = unsafe { [0u8; 100].as_ptr().offset(101) };
-   |                                             ------------------------------- inside `AFTER_ARRAY` at $DIR/offset_ub.rs:9:45
+   |                                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0080]: evaluation of constant value failed
   --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
    |
 LL |         unsafe { intrinsics::offset(self, count) }
-   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |                  |
-   |                  overflowing in-bounds pointer arithmetic
-   |                  inside `ptr::const_ptr::<impl *const u16>::offset` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
+   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflowing in-bounds pointer arithmetic
+   |
+note: inside `ptr::const_ptr::<impl *const u16>::offset`
+  --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
    |
-  ::: $DIR/offset_ub.rs:11:43
+LL |         unsafe { intrinsics::offset(self, count) }
+   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+note: inside `OVERFLOW`
+  --> $DIR/offset_ub.rs:11:43
    |
 LL | pub const OVERFLOW: *const u16 = unsafe { [0u16; 1].as_ptr().offset(isize::MAX) };
-   |                                           ------------------------------------- inside `OVERFLOW` at $DIR/offset_ub.rs:11:43
+   |                                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0080]: evaluation of constant value failed
   --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
    |
 LL |         unsafe { intrinsics::offset(self, count) }
-   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |                  |
-   |                  overflowing in-bounds pointer arithmetic
-   |                  inside `ptr::const_ptr::<impl *const u16>::offset` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
+   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflowing in-bounds pointer arithmetic
    |
-  ::: $DIR/offset_ub.rs:12:44
+note: inside `ptr::const_ptr::<impl *const u16>::offset`
+  --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
+   |
+LL |         unsafe { intrinsics::offset(self, count) }
+   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+note: inside `UNDERFLOW`
+  --> $DIR/offset_ub.rs:12:44
    |
 LL | pub const UNDERFLOW: *const u16 = unsafe { [0u16; 1].as_ptr().offset(isize::MIN) };
-   |                                            ------------------------------------- inside `UNDERFLOW` at $DIR/offset_ub.rs:12:44
+   |                                            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0080]: evaluation of constant value failed
   --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
    |
 LL |         unsafe { intrinsics::offset(self, count) }
-   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |                  |
-   |                  overflowing in-bounds pointer arithmetic
-   |                  inside `ptr::const_ptr::<impl *const u8>::offset` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
+   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflowing in-bounds pointer arithmetic
    |
-  ::: $DIR/offset_ub.rs:13:56
+note: inside `ptr::const_ptr::<impl *const u8>::offset`
+  --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
+   |
+LL |         unsafe { intrinsics::offset(self, count) }
+   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+note: inside `OVERFLOW_ADDRESS_SPACE`
+  --> $DIR/offset_ub.rs:13:56
    |
 LL | pub const OVERFLOW_ADDRESS_SPACE: *const u8 = unsafe { (usize::MAX as *const u8).offset(2) };
-   |                                                        ----------------------------------- inside `OVERFLOW_ADDRESS_SPACE` at $DIR/offset_ub.rs:13:56
+   |                                                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0080]: evaluation of constant value failed
   --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
    |
 LL |         unsafe { intrinsics::offset(self, count) }
-   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |                  |
-   |                  overflowing in-bounds pointer arithmetic
-   |                  inside `ptr::const_ptr::<impl *const u8>::offset` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
+   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflowing in-bounds pointer arithmetic
+   |
+note: inside `ptr::const_ptr::<impl *const u8>::offset`
+  --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
    |
-  ::: $DIR/offset_ub.rs:14:57
+LL |         unsafe { intrinsics::offset(self, count) }
+   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+note: inside `UNDERFLOW_ADDRESS_SPACE`
+  --> $DIR/offset_ub.rs:14:57
    |
 LL | pub const UNDERFLOW_ADDRESS_SPACE: *const u8 = unsafe { (1 as *const u8).offset(-2) };
-   |                                                         --------------------------- inside `UNDERFLOW_ADDRESS_SPACE` at $DIR/offset_ub.rs:14:57
+   |                                                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0080]: evaluation of constant value failed
   --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
    |
 LL |         unsafe { intrinsics::offset(self, count) }
-   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |                  |
-   |                  out-of-bounds pointer arithmetic: allocN has size 1, so pointer to 2 bytes starting at offset -4 is out-of-bounds
-   |                  inside `ptr::const_ptr::<impl *const u8>::offset` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
+   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer arithmetic: allocN has size 1, so pointer to 2 bytes starting at offset -4 is out-of-bounds
    |
-  ::: $DIR/offset_ub.rs:15:49
+note: inside `ptr::const_ptr::<impl *const u8>::offset`
+  --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
+   |
+LL |         unsafe { intrinsics::offset(self, count) }
+   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+note: inside `NEGATIVE_OFFSET`
+  --> $DIR/offset_ub.rs:15:49
    |
 LL | pub const NEGATIVE_OFFSET: *const u8 = unsafe { [0u8; 1].as_ptr().wrapping_offset(-2).offset(-2) };
-   |                                                 ------------------------------------------------ inside `NEGATIVE_OFFSET` at $DIR/offset_ub.rs:15:49
+   |                                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0080]: evaluation of constant value failed
   --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
    |
 LL |         unsafe { intrinsics::offset(self, count) }
-   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |                  |
-   |                  out-of-bounds pointer arithmetic: allocN has size 0, so pointer to 1 byte starting at offset 0 is out-of-bounds
-   |                  inside `ptr::const_ptr::<impl *const u8>::offset` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
+   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer arithmetic: allocN has size 0, so pointer to 1 byte starting at offset 0 is out-of-bounds
    |
-  ::: $DIR/offset_ub.rs:17:50
+note: inside `ptr::const_ptr::<impl *const u8>::offset`
+  --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
+   |
+LL |         unsafe { intrinsics::offset(self, count) }
+   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+note: inside `ZERO_SIZED_ALLOC`
+  --> $DIR/offset_ub.rs:17:50
    |
 LL | pub const ZERO_SIZED_ALLOC: *const u8 = unsafe { [0u8; 0].as_ptr().offset(1) };
-   |                                                  --------------------------- inside `ZERO_SIZED_ALLOC` at $DIR/offset_ub.rs:17:50
+   |                                                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0080]: evaluation of constant value failed
   --> $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL
    |
 LL |         unsafe { intrinsics::offset(self, count) as *mut T }
-   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |                  |
-   |                  out-of-bounds pointer arithmetic: 0x1[noalloc] is a dangling pointer (it has no provenance)
-   |                  inside `ptr::mut_ptr::<impl *mut u8>::offset` at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL
+   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer arithmetic: 0x1[noalloc] is a dangling pointer (it has no provenance)
+   |
+note: inside `ptr::mut_ptr::<impl *mut u8>::offset`
+  --> $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL
    |
-  ::: $DIR/offset_ub.rs:18:42
+LL |         unsafe { intrinsics::offset(self, count) as *mut T }
+   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+note: inside `DANGLING`
+  --> $DIR/offset_ub.rs:18:42
    |
 LL | pub const DANGLING: *const u8 = unsafe { ptr::NonNull::<u8>::dangling().as_ptr().offset(4) };
-   |                                          ------------------------------------------------- inside `DANGLING` at $DIR/offset_ub.rs:18:42
+   |                                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0080]: evaluation of constant value failed
   --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
    |
 LL |         unsafe { intrinsics::offset(self, count) }
-   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |                  |
-   |                  out-of-bounds pointer arithmetic: null pointer is a dangling pointer (it has no provenance)
-   |                  inside `ptr::const_ptr::<impl *const u8>::offset` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
+   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer arithmetic: null pointer is a dangling pointer (it has no provenance)
    |
-  ::: $DIR/offset_ub.rs:21:50
+note: inside `ptr::const_ptr::<impl *const u8>::offset`
+  --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
+   |
+LL |         unsafe { intrinsics::offset(self, count) }
+   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+note: inside `NULL_OFFSET_ZERO`
+  --> $DIR/offset_ub.rs:21:50
    |
 LL | pub const NULL_OFFSET_ZERO: *const u8 = unsafe { ptr::null::<u8>().offset(0) };
-   |                                                  --------------------------- inside `NULL_OFFSET_ZERO` at $DIR/offset_ub.rs:21:50
+   |                                                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0080]: evaluation of constant value failed
   --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
    |
 LL |         unsafe { intrinsics::offset(self, count) }
-   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |                  |
-   |                  out-of-bounds pointer arithmetic: 0x7f..f[noalloc] is a dangling pointer (it has no provenance)
-   |                  inside `ptr::const_ptr::<impl *const u8>::offset` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
+   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer arithmetic: 0x7f..f[noalloc] is a dangling pointer (it has no provenance)
    |
-  ::: $DIR/offset_ub.rs:24:47
+note: inside `ptr::const_ptr::<impl *const u8>::offset`
+  --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
+   |
+LL |         unsafe { intrinsics::offset(self, count) }
+   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+note: inside `UNDERFLOW_ABS`
+  --> $DIR/offset_ub.rs:24:47
    |
 LL | pub const UNDERFLOW_ABS: *const u8 = unsafe { (usize::MAX as *const u8).offset(isize::MIN) };
-   |                                               -------------------------------------------- inside `UNDERFLOW_ABS` at $DIR/offset_ub.rs:24:47
+   |                                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to 12 previous errors
 
index b71964b92c77315ac67ff3b4c1dd41ff2e28c283..274753ef1bc234c4a5cae52520870ec906aa6085 100644 (file)
@@ -2,15 +2,18 @@ error[E0080]: evaluation of constant value failed
   --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
    |
 LL |         unsafe { intrinsics::offset(self, count) }
-   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |                  |
-   |                  out-of-bounds pointer arithmetic: alloc3 has size $WORD, so pointer to $TWO_WORDS bytes starting at offset 0 is out-of-bounds
-   |                  inside `ptr::const_ptr::<impl *const usize>::offset` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
+   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer arithmetic: alloc3 has size $WORD, so pointer to $TWO_WORDS bytes starting at offset 0 is out-of-bounds
+   |
+note: inside `ptr::const_ptr::<impl *const usize>::offset`
+  --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
    |
-  ::: $DIR/ptr_comparisons.rs:50:34
+LL |         unsafe { intrinsics::offset(self, count) }
+   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+note: inside `_`
+  --> $DIR/ptr_comparisons.rs:50:34
    |
 LL | const _: *const usize = unsafe { (FOO as *const usize).offset(2) };
-   |                                  ------------------------------- inside `_` at $DIR/ptr_comparisons.rs:50:34
+   |                                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0080]: evaluation of constant value failed
   --> $DIR/ptr_comparisons.rs:53:33
index 14fa3da7ab0f2e3099ad58fa394936434c57732b..60ce64d2a1e0f4dd864a8d565bc61cd13718cfc7 100644 (file)
@@ -12,15 +12,24 @@ LL |     f(x);
 error[E0080]: evaluation of constant value failed
   --> $DIR/recursive.rs:4:5
    |
+LL |     f(x);
+   |     ^^^^ reached the configured maximum number of stack frames
+   |
+note: inside `f::<i32>`
+  --> $DIR/recursive.rs:4:5
+   |
 LL |     f(x);
    |     ^^^^
-   |     |
-   |     reached the configured maximum number of stack frames
-   |     inside `f::<i32>` at $DIR/recursive.rs:4:5
-   |     [... 126 additional calls inside `f::<i32>` at $DIR/recursive.rs:4:5 ...]
-...
+note: [... 126 additional calls inside `f::<i32>` ...]
+  --> $DIR/recursive.rs:4:5
+   |
+LL |     f(x);
+   |     ^^^^
+note: inside `X`
+  --> $DIR/recursive.rs:8:15
+   |
 LL | const X: () = f(1);
-   |               ---- inside `X` at $DIR/recursive.rs:8:15
+   |               ^^^^
 
 error: aborting due to previous error; 1 warning emitted
 
index 8b39f390bb47eb9ba0ba4c26e2d9d5cf575c7650..3a94e19313f6c52b719ead4dddf54b6e1872822c 100644 (file)
 error[E0080]: evaluation of `<i32 as Const>::CONSTANT` failed
   --> $DIR/uninhabited-const-issue-61744.rs:4:5
    |
+LL |     hint_unreachable()
+   |     ^^^^^^^^^^^^^^^^^^ reached the configured maximum number of stack frames
+   |
+note: inside `fake_type::<!>`
+  --> $DIR/uninhabited-const-issue-61744.rs:4:5
+   |
+LL |     hint_unreachable()
+   |     ^^^^^^^^^^^^^^^^^^
+note: inside `hint_unreachable`
+  --> $DIR/uninhabited-const-issue-61744.rs:8:5
+   |
+LL |     fake_type()
+   |     ^^^^^^^^^^^
+note: inside `fake_type::<!>`
+  --> $DIR/uninhabited-const-issue-61744.rs:4:5
+   |
+LL |     hint_unreachable()
+   |     ^^^^^^^^^^^^^^^^^^
+note: inside `hint_unreachable`
+  --> $DIR/uninhabited-const-issue-61744.rs:8:5
+   |
+LL |     fake_type()
+   |     ^^^^^^^^^^^
+note: inside `fake_type::<!>`
+  --> $DIR/uninhabited-const-issue-61744.rs:4:5
+   |
+LL |     hint_unreachable()
+   |     ^^^^^^^^^^^^^^^^^^
+note: inside `hint_unreachable`
+  --> $DIR/uninhabited-const-issue-61744.rs:8:5
+   |
+LL |     fake_type()
+   |     ^^^^^^^^^^^
+note: inside `fake_type::<!>`
+  --> $DIR/uninhabited-const-issue-61744.rs:4:5
+   |
+LL |     hint_unreachable()
+   |     ^^^^^^^^^^^^^^^^^^
+note: inside `hint_unreachable`
+  --> $DIR/uninhabited-const-issue-61744.rs:8:5
+   |
+LL |     fake_type()
+   |     ^^^^^^^^^^^
+note: inside `fake_type::<!>`
+  --> $DIR/uninhabited-const-issue-61744.rs:4:5
+   |
+LL |     hint_unreachable()
+   |     ^^^^^^^^^^^^^^^^^^
+note: inside `hint_unreachable`
+  --> $DIR/uninhabited-const-issue-61744.rs:8:5
+   |
+LL |     fake_type()
+   |     ^^^^^^^^^^^
+note: inside `fake_type::<!>`
+  --> $DIR/uninhabited-const-issue-61744.rs:4:5
+   |
+LL |     hint_unreachable()
+   |     ^^^^^^^^^^^^^^^^^^
+note: inside `hint_unreachable`
+  --> $DIR/uninhabited-const-issue-61744.rs:8:5
+   |
+LL |     fake_type()
+   |     ^^^^^^^^^^^
+note: inside `fake_type::<!>`
+  --> $DIR/uninhabited-const-issue-61744.rs:4:5
+   |
+LL |     hint_unreachable()
+   |     ^^^^^^^^^^^^^^^^^^
+note: inside `hint_unreachable`
+  --> $DIR/uninhabited-const-issue-61744.rs:8:5
+   |
+LL |     fake_type()
+   |     ^^^^^^^^^^^
+note: inside `fake_type::<!>`
+  --> $DIR/uninhabited-const-issue-61744.rs:4:5
+   |
+LL |     hint_unreachable()
+   |     ^^^^^^^^^^^^^^^^^^
+note: inside `hint_unreachable`
+  --> $DIR/uninhabited-const-issue-61744.rs:8:5
+   |
+LL |     fake_type()
+   |     ^^^^^^^^^^^
+note: inside `fake_type::<!>`
+  --> $DIR/uninhabited-const-issue-61744.rs:4:5
+   |
+LL |     hint_unreachable()
+   |     ^^^^^^^^^^^^^^^^^^
+note: inside `hint_unreachable`
+  --> $DIR/uninhabited-const-issue-61744.rs:8:5
+   |
+LL |     fake_type()
+   |     ^^^^^^^^^^^
+note: inside `fake_type::<!>`
+  --> $DIR/uninhabited-const-issue-61744.rs:4:5
+   |
+LL |     hint_unreachable()
+   |     ^^^^^^^^^^^^^^^^^^
+note: inside `hint_unreachable`
+  --> $DIR/uninhabited-const-issue-61744.rs:8:5
+   |
+LL |     fake_type()
+   |     ^^^^^^^^^^^
+note: inside `fake_type::<!>`
+  --> $DIR/uninhabited-const-issue-61744.rs:4:5
+   |
+LL |     hint_unreachable()
+   |     ^^^^^^^^^^^^^^^^^^
+note: inside `hint_unreachable`
+  --> $DIR/uninhabited-const-issue-61744.rs:8:5
+   |
+LL |     fake_type()
+   |     ^^^^^^^^^^^
+note: inside `fake_type::<!>`
+  --> $DIR/uninhabited-const-issue-61744.rs:4:5
+   |
+LL |     hint_unreachable()
+   |     ^^^^^^^^^^^^^^^^^^
+note: inside `hint_unreachable`
+  --> $DIR/uninhabited-const-issue-61744.rs:8:5
+   |
+LL |     fake_type()
+   |     ^^^^^^^^^^^
+note: inside `fake_type::<!>`
+  --> $DIR/uninhabited-const-issue-61744.rs:4:5
+   |
+LL |     hint_unreachable()
+   |     ^^^^^^^^^^^^^^^^^^
+note: inside `hint_unreachable`
+  --> $DIR/uninhabited-const-issue-61744.rs:8:5
+   |
+LL |     fake_type()
+   |     ^^^^^^^^^^^
+note: inside `fake_type::<!>`
+  --> $DIR/uninhabited-const-issue-61744.rs:4:5
+   |
+LL |     hint_unreachable()
+   |     ^^^^^^^^^^^^^^^^^^
+note: inside `hint_unreachable`
+  --> $DIR/uninhabited-const-issue-61744.rs:8:5
+   |
+LL |     fake_type()
+   |     ^^^^^^^^^^^
+note: inside `fake_type::<!>`
+  --> $DIR/uninhabited-const-issue-61744.rs:4:5
+   |
+LL |     hint_unreachable()
+   |     ^^^^^^^^^^^^^^^^^^
+note: inside `hint_unreachable`
+  --> $DIR/uninhabited-const-issue-61744.rs:8:5
+   |
+LL |     fake_type()
+   |     ^^^^^^^^^^^
+note: inside `fake_type::<!>`
+  --> $DIR/uninhabited-const-issue-61744.rs:4:5
+   |
+LL |     hint_unreachable()
+   |     ^^^^^^^^^^^^^^^^^^
+note: inside `hint_unreachable`
+  --> $DIR/uninhabited-const-issue-61744.rs:8:5
+   |
+LL |     fake_type()
+   |     ^^^^^^^^^^^
+note: inside `fake_type::<!>`
+  --> $DIR/uninhabited-const-issue-61744.rs:4:5
+   |
+LL |     hint_unreachable()
+   |     ^^^^^^^^^^^^^^^^^^
+note: inside `hint_unreachable`
+  --> $DIR/uninhabited-const-issue-61744.rs:8:5
+   |
+LL |     fake_type()
+   |     ^^^^^^^^^^^
+note: inside `fake_type::<!>`
+  --> $DIR/uninhabited-const-issue-61744.rs:4:5
+   |
+LL |     hint_unreachable()
+   |     ^^^^^^^^^^^^^^^^^^
+note: inside `hint_unreachable`
+  --> $DIR/uninhabited-const-issue-61744.rs:8:5
+   |
+LL |     fake_type()
+   |     ^^^^^^^^^^^
+note: inside `fake_type::<!>`
+  --> $DIR/uninhabited-const-issue-61744.rs:4:5
+   |
+LL |     hint_unreachable()
+   |     ^^^^^^^^^^^^^^^^^^
+note: inside `hint_unreachable`
+  --> $DIR/uninhabited-const-issue-61744.rs:8:5
+   |
+LL |     fake_type()
+   |     ^^^^^^^^^^^
+note: inside `fake_type::<!>`
+  --> $DIR/uninhabited-const-issue-61744.rs:4:5
+   |
+LL |     hint_unreachable()
+   |     ^^^^^^^^^^^^^^^^^^
+note: inside `hint_unreachable`
+  --> $DIR/uninhabited-const-issue-61744.rs:8:5
+   |
+LL |     fake_type()
+   |     ^^^^^^^^^^^
+note: inside `fake_type::<!>`
+  --> $DIR/uninhabited-const-issue-61744.rs:4:5
+   |
+LL |     hint_unreachable()
+   |     ^^^^^^^^^^^^^^^^^^
+note: inside `hint_unreachable`
+  --> $DIR/uninhabited-const-issue-61744.rs:8:5
+   |
+LL |     fake_type()
+   |     ^^^^^^^^^^^
+note: inside `fake_type::<!>`
+  --> $DIR/uninhabited-const-issue-61744.rs:4:5
+   |
+LL |     hint_unreachable()
+   |     ^^^^^^^^^^^^^^^^^^
+note: inside `hint_unreachable`
+  --> $DIR/uninhabited-const-issue-61744.rs:8:5
+   |
+LL |     fake_type()
+   |     ^^^^^^^^^^^
+note: inside `fake_type::<!>`
+  --> $DIR/uninhabited-const-issue-61744.rs:4:5
+   |
+LL |     hint_unreachable()
+   |     ^^^^^^^^^^^^^^^^^^
+note: inside `hint_unreachable`
+  --> $DIR/uninhabited-const-issue-61744.rs:8:5
+   |
+LL |     fake_type()
+   |     ^^^^^^^^^^^
+note: inside `fake_type::<!>`
+  --> $DIR/uninhabited-const-issue-61744.rs:4:5
+   |
+LL |     hint_unreachable()
+   |     ^^^^^^^^^^^^^^^^^^
+note: inside `hint_unreachable`
+  --> $DIR/uninhabited-const-issue-61744.rs:8:5
+   |
+LL |     fake_type()
+   |     ^^^^^^^^^^^
+note: inside `fake_type::<!>`
+  --> $DIR/uninhabited-const-issue-61744.rs:4:5
+   |
+LL |     hint_unreachable()
+   |     ^^^^^^^^^^^^^^^^^^
+note: inside `hint_unreachable`
+  --> $DIR/uninhabited-const-issue-61744.rs:8:5
+   |
+LL |     fake_type()
+   |     ^^^^^^^^^^^
+note: inside `fake_type::<!>`
+  --> $DIR/uninhabited-const-issue-61744.rs:4:5
+   |
+LL |     hint_unreachable()
+   |     ^^^^^^^^^^^^^^^^^^
+note: inside `hint_unreachable`
+  --> $DIR/uninhabited-const-issue-61744.rs:8:5
+   |
+LL |     fake_type()
+   |     ^^^^^^^^^^^
+note: inside `fake_type::<!>`
+  --> $DIR/uninhabited-const-issue-61744.rs:4:5
+   |
+LL |     hint_unreachable()
+   |     ^^^^^^^^^^^^^^^^^^
+note: inside `hint_unreachable`
+  --> $DIR/uninhabited-const-issue-61744.rs:8:5
+   |
+LL |     fake_type()
+   |     ^^^^^^^^^^^
+note: inside `fake_type::<!>`
+  --> $DIR/uninhabited-const-issue-61744.rs:4:5
+   |
+LL |     hint_unreachable()
+   |     ^^^^^^^^^^^^^^^^^^
+note: inside `hint_unreachable`
+  --> $DIR/uninhabited-const-issue-61744.rs:8:5
+   |
+LL |     fake_type()
+   |     ^^^^^^^^^^^
+note: inside `fake_type::<!>`
+  --> $DIR/uninhabited-const-issue-61744.rs:4:5
+   |
+LL |     hint_unreachable()
+   |     ^^^^^^^^^^^^^^^^^^
+note: inside `hint_unreachable`
+  --> $DIR/uninhabited-const-issue-61744.rs:8:5
+   |
+LL |     fake_type()
+   |     ^^^^^^^^^^^
+note: inside `fake_type::<!>`
+  --> $DIR/uninhabited-const-issue-61744.rs:4:5
+   |
+LL |     hint_unreachable()
+   |     ^^^^^^^^^^^^^^^^^^
+note: inside `hint_unreachable`
+  --> $DIR/uninhabited-const-issue-61744.rs:8:5
+   |
+LL |     fake_type()
+   |     ^^^^^^^^^^^
+note: inside `fake_type::<!>`
+  --> $DIR/uninhabited-const-issue-61744.rs:4:5
+   |
+LL |     hint_unreachable()
+   |     ^^^^^^^^^^^^^^^^^^
+note: inside `hint_unreachable`
+  --> $DIR/uninhabited-const-issue-61744.rs:8:5
+   |
+LL |     fake_type()
+   |     ^^^^^^^^^^^
+note: inside `fake_type::<!>`
+  --> $DIR/uninhabited-const-issue-61744.rs:4:5
+   |
 LL |     hint_unreachable()
    |     ^^^^^^^^^^^^^^^^^^
-   |     |
-   |     reached the configured maximum number of stack frames
-   |     inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5
-   |     inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5
-   |     inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5
-   |     inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5
-   |     inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5
-   |     inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5
-   |     inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5
-   |     inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5
-   |     inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5
-   |     inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5
-   |     inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5
-   |     inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5
-   |     inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5
-   |     inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5
-   |     inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5
-   |     inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5
-   |     inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5
-   |     inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5
-   |     inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5
-   |     inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5
-   |     inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5
-   |     inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5
-   |     inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5
-   |     inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5
-   |     inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5
-   |     inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5
-   |     inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5
-   |     inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5
-   |     inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5
-   |     inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5
-   |     inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5
-   |     inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5
-   |     inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5
-   |     inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5
-   |     inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5
-   |     inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5
-   |     inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5
-   |     inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5
-   |     inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5
-   |     inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5
-   |     inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5
-   |     inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5
-   |     inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5
-   |     inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5
-   |     inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5
-   |     inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5
-   |     inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5
-   |     inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5
-   |     inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5
-   |     inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5
-   |     inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5
-   |     inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5
-   |     inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5
-   |     inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5
-   |     inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5
-   |     inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5
-   |     inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5
-   |     inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5
-   |     inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5
-   |     inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5
-   |     inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5
-   |     inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5
-   |     inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5
-   |     inside `fake_type::<i32>` at $DIR/uninhabited-const-issue-61744.rs:4:5
-...
-LL |     fake_type()
-   |     -----------
-   |     |
-   |     inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5
-   |     inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5
-   |     inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5
-   |     inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5
-   |     inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5
-   |     inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5
-   |     inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5
-   |     inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5
-   |     inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5
-   |     inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5
-   |     inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5
-   |     inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5
-   |     inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5
-   |     inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5
-   |     inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5
-   |     inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5
-   |     inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5
-   |     inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5
-   |     inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5
-   |     inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5
-   |     inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5
-   |     inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5
-   |     inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5
-   |     inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5
-   |     inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5
-   |     inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5
-   |     inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5
-   |     inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5
-   |     inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5
-   |     inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5
-   |     inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5
-   |     inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5
-   |     inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5
-   |     inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5
-   |     inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5
-   |     inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5
-   |     inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5
-   |     inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5
-   |     inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5
-   |     inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5
-   |     inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5
-   |     inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5
-   |     inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5
-   |     inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5
-   |     inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5
-   |     inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5
-   |     inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5
-   |     inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5
-   |     inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5
-   |     inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5
-   |     inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5
-   |     inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5
-   |     inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5
-   |     inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5
-   |     inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5
-   |     inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5
-   |     inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5
-   |     inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5
-   |     inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5
-   |     inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5
-   |     inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5
-   |     inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5
-   |     inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5
-...
+note: inside `hint_unreachable`
+  --> $DIR/uninhabited-const-issue-61744.rs:8:5
+   |
+LL |     fake_type()
+   |     ^^^^^^^^^^^
+note: inside `fake_type::<!>`
+  --> $DIR/uninhabited-const-issue-61744.rs:4:5
+   |
+LL |     hint_unreachable()
+   |     ^^^^^^^^^^^^^^^^^^
+note: inside `hint_unreachable`
+  --> $DIR/uninhabited-const-issue-61744.rs:8:5
+   |
+LL |     fake_type()
+   |     ^^^^^^^^^^^
+note: inside `fake_type::<!>`
+  --> $DIR/uninhabited-const-issue-61744.rs:4:5
+   |
+LL |     hint_unreachable()
+   |     ^^^^^^^^^^^^^^^^^^
+note: inside `hint_unreachable`
+  --> $DIR/uninhabited-const-issue-61744.rs:8:5
+   |
+LL |     fake_type()
+   |     ^^^^^^^^^^^
+note: inside `fake_type::<!>`
+  --> $DIR/uninhabited-const-issue-61744.rs:4:5
+   |
+LL |     hint_unreachable()
+   |     ^^^^^^^^^^^^^^^^^^
+note: inside `hint_unreachable`
+  --> $DIR/uninhabited-const-issue-61744.rs:8:5
+   |
+LL |     fake_type()
+   |     ^^^^^^^^^^^
+note: inside `fake_type::<!>`
+  --> $DIR/uninhabited-const-issue-61744.rs:4:5
+   |
+LL |     hint_unreachable()
+   |     ^^^^^^^^^^^^^^^^^^
+note: inside `hint_unreachable`
+  --> $DIR/uninhabited-const-issue-61744.rs:8:5
+   |
+LL |     fake_type()
+   |     ^^^^^^^^^^^
+note: inside `fake_type::<!>`
+  --> $DIR/uninhabited-const-issue-61744.rs:4:5
+   |
+LL |     hint_unreachable()
+   |     ^^^^^^^^^^^^^^^^^^
+note: inside `hint_unreachable`
+  --> $DIR/uninhabited-const-issue-61744.rs:8:5
+   |
+LL |     fake_type()
+   |     ^^^^^^^^^^^
+note: inside `fake_type::<!>`
+  --> $DIR/uninhabited-const-issue-61744.rs:4:5
+   |
+LL |     hint_unreachable()
+   |     ^^^^^^^^^^^^^^^^^^
+note: inside `hint_unreachable`
+  --> $DIR/uninhabited-const-issue-61744.rs:8:5
+   |
+LL |     fake_type()
+   |     ^^^^^^^^^^^
+note: inside `fake_type::<!>`
+  --> $DIR/uninhabited-const-issue-61744.rs:4:5
+   |
+LL |     hint_unreachable()
+   |     ^^^^^^^^^^^^^^^^^^
+note: inside `hint_unreachable`
+  --> $DIR/uninhabited-const-issue-61744.rs:8:5
+   |
+LL |     fake_type()
+   |     ^^^^^^^^^^^
+note: inside `fake_type::<!>`
+  --> $DIR/uninhabited-const-issue-61744.rs:4:5
+   |
+LL |     hint_unreachable()
+   |     ^^^^^^^^^^^^^^^^^^
+note: inside `hint_unreachable`
+  --> $DIR/uninhabited-const-issue-61744.rs:8:5
+   |
+LL |     fake_type()
+   |     ^^^^^^^^^^^
+note: inside `fake_type::<!>`
+  --> $DIR/uninhabited-const-issue-61744.rs:4:5
+   |
+LL |     hint_unreachable()
+   |     ^^^^^^^^^^^^^^^^^^
+note: inside `hint_unreachable`
+  --> $DIR/uninhabited-const-issue-61744.rs:8:5
+   |
+LL |     fake_type()
+   |     ^^^^^^^^^^^
+note: inside `fake_type::<!>`
+  --> $DIR/uninhabited-const-issue-61744.rs:4:5
+   |
+LL |     hint_unreachable()
+   |     ^^^^^^^^^^^^^^^^^^
+note: inside `hint_unreachable`
+  --> $DIR/uninhabited-const-issue-61744.rs:8:5
+   |
+LL |     fake_type()
+   |     ^^^^^^^^^^^
+note: inside `fake_type::<!>`
+  --> $DIR/uninhabited-const-issue-61744.rs:4:5
+   |
+LL |     hint_unreachable()
+   |     ^^^^^^^^^^^^^^^^^^
+note: inside `hint_unreachable`
+  --> $DIR/uninhabited-const-issue-61744.rs:8:5
+   |
+LL |     fake_type()
+   |     ^^^^^^^^^^^
+note: inside `fake_type::<!>`
+  --> $DIR/uninhabited-const-issue-61744.rs:4:5
+   |
+LL |     hint_unreachable()
+   |     ^^^^^^^^^^^^^^^^^^
+note: inside `hint_unreachable`
+  --> $DIR/uninhabited-const-issue-61744.rs:8:5
+   |
+LL |     fake_type()
+   |     ^^^^^^^^^^^
+note: inside `fake_type::<!>`
+  --> $DIR/uninhabited-const-issue-61744.rs:4:5
+   |
+LL |     hint_unreachable()
+   |     ^^^^^^^^^^^^^^^^^^
+note: inside `hint_unreachable`
+  --> $DIR/uninhabited-const-issue-61744.rs:8:5
+   |
+LL |     fake_type()
+   |     ^^^^^^^^^^^
+note: inside `fake_type::<!>`
+  --> $DIR/uninhabited-const-issue-61744.rs:4:5
+   |
+LL |     hint_unreachable()
+   |     ^^^^^^^^^^^^^^^^^^
+note: inside `hint_unreachable`
+  --> $DIR/uninhabited-const-issue-61744.rs:8:5
+   |
+LL |     fake_type()
+   |     ^^^^^^^^^^^
+note: inside `fake_type::<!>`
+  --> $DIR/uninhabited-const-issue-61744.rs:4:5
+   |
+LL |     hint_unreachable()
+   |     ^^^^^^^^^^^^^^^^^^
+note: inside `hint_unreachable`
+  --> $DIR/uninhabited-const-issue-61744.rs:8:5
+   |
+LL |     fake_type()
+   |     ^^^^^^^^^^^
+note: inside `fake_type::<!>`
+  --> $DIR/uninhabited-const-issue-61744.rs:4:5
+   |
+LL |     hint_unreachable()
+   |     ^^^^^^^^^^^^^^^^^^
+note: inside `hint_unreachable`
+  --> $DIR/uninhabited-const-issue-61744.rs:8:5
+   |
+LL |     fake_type()
+   |     ^^^^^^^^^^^
+note: inside `fake_type::<!>`
+  --> $DIR/uninhabited-const-issue-61744.rs:4:5
+   |
+LL |     hint_unreachable()
+   |     ^^^^^^^^^^^^^^^^^^
+note: inside `hint_unreachable`
+  --> $DIR/uninhabited-const-issue-61744.rs:8:5
+   |
+LL |     fake_type()
+   |     ^^^^^^^^^^^
+note: inside `fake_type::<!>`
+  --> $DIR/uninhabited-const-issue-61744.rs:4:5
+   |
+LL |     hint_unreachable()
+   |     ^^^^^^^^^^^^^^^^^^
+note: inside `hint_unreachable`
+  --> $DIR/uninhabited-const-issue-61744.rs:8:5
+   |
+LL |     fake_type()
+   |     ^^^^^^^^^^^
+note: inside `fake_type::<!>`
+  --> $DIR/uninhabited-const-issue-61744.rs:4:5
+   |
+LL |     hint_unreachable()
+   |     ^^^^^^^^^^^^^^^^^^
+note: inside `hint_unreachable`
+  --> $DIR/uninhabited-const-issue-61744.rs:8:5
+   |
+LL |     fake_type()
+   |     ^^^^^^^^^^^
+note: inside `fake_type::<!>`
+  --> $DIR/uninhabited-const-issue-61744.rs:4:5
+   |
+LL |     hint_unreachable()
+   |     ^^^^^^^^^^^^^^^^^^
+note: inside `hint_unreachable`
+  --> $DIR/uninhabited-const-issue-61744.rs:8:5
+   |
+LL |     fake_type()
+   |     ^^^^^^^^^^^
+note: inside `fake_type::<!>`
+  --> $DIR/uninhabited-const-issue-61744.rs:4:5
+   |
+LL |     hint_unreachable()
+   |     ^^^^^^^^^^^^^^^^^^
+note: inside `hint_unreachable`
+  --> $DIR/uninhabited-const-issue-61744.rs:8:5
+   |
+LL |     fake_type()
+   |     ^^^^^^^^^^^
+note: inside `fake_type::<!>`
+  --> $DIR/uninhabited-const-issue-61744.rs:4:5
+   |
+LL |     hint_unreachable()
+   |     ^^^^^^^^^^^^^^^^^^
+note: inside `hint_unreachable`
+  --> $DIR/uninhabited-const-issue-61744.rs:8:5
+   |
+LL |     fake_type()
+   |     ^^^^^^^^^^^
+note: inside `fake_type::<!>`
+  --> $DIR/uninhabited-const-issue-61744.rs:4:5
+   |
+LL |     hint_unreachable()
+   |     ^^^^^^^^^^^^^^^^^^
+note: inside `hint_unreachable`
+  --> $DIR/uninhabited-const-issue-61744.rs:8:5
+   |
+LL |     fake_type()
+   |     ^^^^^^^^^^^
+note: inside `fake_type::<!>`
+  --> $DIR/uninhabited-const-issue-61744.rs:4:5
+   |
+LL |     hint_unreachable()
+   |     ^^^^^^^^^^^^^^^^^^
+note: inside `hint_unreachable`
+  --> $DIR/uninhabited-const-issue-61744.rs:8:5
+   |
+LL |     fake_type()
+   |     ^^^^^^^^^^^
+note: inside `fake_type::<!>`
+  --> $DIR/uninhabited-const-issue-61744.rs:4:5
+   |
+LL |     hint_unreachable()
+   |     ^^^^^^^^^^^^^^^^^^
+note: inside `hint_unreachable`
+  --> $DIR/uninhabited-const-issue-61744.rs:8:5
+   |
+LL |     fake_type()
+   |     ^^^^^^^^^^^
+note: inside `fake_type::<!>`
+  --> $DIR/uninhabited-const-issue-61744.rs:4:5
+   |
+LL |     hint_unreachable()
+   |     ^^^^^^^^^^^^^^^^^^
+note: inside `hint_unreachable`
+  --> $DIR/uninhabited-const-issue-61744.rs:8:5
+   |
+LL |     fake_type()
+   |     ^^^^^^^^^^^
+note: inside `fake_type::<!>`
+  --> $DIR/uninhabited-const-issue-61744.rs:4:5
+   |
+LL |     hint_unreachable()
+   |     ^^^^^^^^^^^^^^^^^^
+note: inside `hint_unreachable`
+  --> $DIR/uninhabited-const-issue-61744.rs:8:5
+   |
+LL |     fake_type()
+   |     ^^^^^^^^^^^
+note: inside `fake_type::<!>`
+  --> $DIR/uninhabited-const-issue-61744.rs:4:5
+   |
+LL |     hint_unreachable()
+   |     ^^^^^^^^^^^^^^^^^^
+note: inside `hint_unreachable`
+  --> $DIR/uninhabited-const-issue-61744.rs:8:5
+   |
+LL |     fake_type()
+   |     ^^^^^^^^^^^
+note: inside `fake_type::<!>`
+  --> $DIR/uninhabited-const-issue-61744.rs:4:5
+   |
+LL |     hint_unreachable()
+   |     ^^^^^^^^^^^^^^^^^^
+note: inside `hint_unreachable`
+  --> $DIR/uninhabited-const-issue-61744.rs:8:5
+   |
+LL |     fake_type()
+   |     ^^^^^^^^^^^
+note: inside `fake_type::<!>`
+  --> $DIR/uninhabited-const-issue-61744.rs:4:5
+   |
+LL |     hint_unreachable()
+   |     ^^^^^^^^^^^^^^^^^^
+note: inside `hint_unreachable`
+  --> $DIR/uninhabited-const-issue-61744.rs:8:5
+   |
+LL |     fake_type()
+   |     ^^^^^^^^^^^
+note: inside `fake_type::<!>`
+  --> $DIR/uninhabited-const-issue-61744.rs:4:5
+   |
+LL |     hint_unreachable()
+   |     ^^^^^^^^^^^^^^^^^^
+note: inside `hint_unreachable`
+  --> $DIR/uninhabited-const-issue-61744.rs:8:5
+   |
+LL |     fake_type()
+   |     ^^^^^^^^^^^
+note: inside `fake_type::<i32>`
+  --> $DIR/uninhabited-const-issue-61744.rs:4:5
+   |
+LL |     hint_unreachable()
+   |     ^^^^^^^^^^^^^^^^^^
+note: inside `<i32 as Const>::CONSTANT`
+  --> $DIR/uninhabited-const-issue-61744.rs:12:36
+   |
 LL |     const CONSTANT: i32 = unsafe { fake_type() };
-   |                                    ----------- inside `<i32 as Const>::CONSTANT` at $DIR/uninhabited-const-issue-61744.rs:12:36
+   |                                    ^^^^^^^^^^^
 
 note: erroneous constant used
   --> $DIR/uninhabited-const-issue-61744.rs:18:10
diff --git a/src/test/ui/debuginfo/issue-105386-debuginfo-ub.rs b/src/test/ui/debuginfo/issue-105386-debuginfo-ub.rs
new file mode 100644 (file)
index 0000000..6c6eb5d
--- /dev/null
@@ -0,0 +1,20 @@
+// run-pass
+// compile-flags: --edition 2021 -Copt-level=3 -Cdebuginfo=2 -Zmir-opt-level=3
+
+fn main() {
+    TranslatorI.visit_pre();
+}
+
+impl TranslatorI {
+    fn visit_pre(self) {
+        Some(())
+            .map(|_| self.flags())
+            .unwrap_or_else(|| self.flags());
+    }
+}
+
+struct TranslatorI;
+
+impl TranslatorI {
+    fn flags(&self) {}
+}
diff --git a/src/test/ui/diagnostic-width/long-E0308.rs b/src/test/ui/diagnostic-width/long-E0308.rs
new file mode 100644 (file)
index 0000000..f021f10
--- /dev/null
@@ -0,0 +1,97 @@
+// compile-flags: --diagnostic-width=60
+// normalize-stderr-test: "long-type-\d+" -> "long-type-hash"
+
+mod a {
+    // Force the "short path for unique types" machinery to trip up
+    pub struct Atype;
+    pub struct Btype;
+    pub struct Ctype;
+}
+
+mod b {
+    pub struct Atype<T, K>(T, K);
+    pub struct Btype<T, K>(T, K);
+    pub struct Ctype<T, K>(T, K);
+}
+
+use b::*;
+
+fn main() {
+    let x: Atype<
+      Btype<
+        Ctype<
+          Atype<
+            Btype<
+              Ctype<
+                Atype<
+                  Btype<
+                    Ctype<i32, i32>,
+                    i32
+                  >,
+                  i32
+                >,
+                i32
+              >,
+              i32
+            >,
+            i32
+          >,
+          i32
+        >,
+        i32
+      >,
+      i32
+    > = Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(
+        Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(
+            Ok("")
+        ))))))))))))))))))))))))))))))
+    ))))))))))))))))))))))))))))));
+    //~^^^^^ ERROR E0308
+
+    let _ = Some(Ok(Some(Some(Some(Some(Some(Some(Some(Some(Some(Some(Some(Some(Some(Some(Some(
+        Some(Some(Some(Some(Some(Some(Some(Some(Some(Some(Some(Some(Some(Some(Some(Some(Some(Some(
+            Some(Some(Some(Some(Some(Some(Some(Some(Some(Some(Some(Some(Some(Some(Some(Some(Some(
+                Some(Some(Some(Some(Some(Some(Some(Some(Some("")))))))))
+            )))))))))))))))))
+        ))))))))))))))))))
+    ))))))))))))))))) == Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(
+        Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(
+            Ok(Ok(Ok(Ok(Ok(Ok(Ok("")))))))
+        ))))))))))))))))))))))))))))))
+    ))))))))))))))))))))))));
+    //~^^^^^ ERROR E0308
+
+    let x: Atype<
+      Btype<
+        Ctype<
+          Atype<
+            Btype<
+              Ctype<
+                Atype<
+                  Btype<
+                    Ctype<i32, i32>,
+                    i32
+                  >,
+                  i32
+                >,
+                i32
+              >,
+              i32
+            >,
+            i32
+          >,
+          i32
+        >,
+        i32
+      >,
+      i32
+    > = ();
+    //~^ ERROR E0308
+
+    let _: () = Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(
+        Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(
+            Ok(Ok(Ok(Ok(Ok(Ok(Ok("")))))))
+        ))))))))))))))))))))))))))))))
+    ))))))))))))))))))))))));
+    //~^^^^^ ERROR E0308
+}
diff --git a/src/test/ui/diagnostic-width/long-E0308.stderr b/src/test/ui/diagnostic-width/long-E0308.stderr
new file mode 100644 (file)
index 0000000..1c99898
--- /dev/null
@@ -0,0 +1,80 @@
+error[E0308]: mismatched types
+  --> $DIR/long-E0308.rs:44:9
+   |
+LL |        let x: Atype<
+   |  _____________-
+LL | |        Btype<
+LL | |          Ctype<
+LL | |            Atype<
+...  |
+LL | |        i32
+LL | |      > = Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok...
+   | | _____-___^
+   | ||_____|
+   |  |     expected due to this
+LL |  |         Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok...
+LL |  |             Ok("")
+LL |  |         ))))))))))))))))))))))))))))))
+LL |  |     ))))))))))))))))))))))))))))));
+   |  |__________________________________^ expected struct `Atype`, found enum `Result`
+   |
+   = note: expected struct `Atype<Btype<..., ...>, ...>`
+           the full type name has been written to '$TEST_BUILD_DIR/diagnostic-width/long-E0308/long-E0308.long-type-hash.txt'
+                found enum `Result<Result<..., ...>, ...>`
+           the full type name has been written to '$TEST_BUILD_DIR/diagnostic-width/long-E0308/long-E0308.long-type-hash.txt'
+
+error[E0308]: mismatched types
+  --> $DIR/long-E0308.rs:57:26
+   |
+LL |       ))))))))))))))))) == Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(O...
+   |  __________________________^
+LL | |         Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(...
+LL | |             Ok(Ok(Ok(Ok(Ok(Ok(Ok("")))))))
+LL | |         ))))))))))))))))))))))))))))))
+LL | |     ))))))))))))))))))))))));
+   | |____________________________^ expected enum `Option`, found enum `Result`
+   |
+   = note: expected enum `Option<Result<..., ...>>`
+           the full type name has been written to '$TEST_BUILD_DIR/diagnostic-width/long-E0308/long-E0308.long-type-hash.txt'
+              found enum `Result<Result<..., ...>, ...>`
+           the full type name has been written to '$TEST_BUILD_DIR/diagnostic-width/long-E0308/long-E0308.long-type-hash.txt'
+
+error[E0308]: mismatched types
+  --> $DIR/long-E0308.rs:88:9
+   |
+LL |       let x: Atype<
+   |  ____________-
+LL | |       Btype<
+LL | |         Ctype<
+LL | |           Atype<
+...  |
+LL | |       i32
+LL | |     > = ();
+   | |     -   ^^ expected struct `Atype`, found `()`
+   | |_____|
+   |       expected due to this
+   |
+   = note: expected struct `Atype<Btype<..., ...>, ...>`
+           the full type name has been written to '$TEST_BUILD_DIR/diagnostic-width/long-E0308/long-E0308.long-type-hash.txt'
+           found unit type `()`
+
+error[E0308]: mismatched types
+  --> $DIR/long-E0308.rs:91:17
+   |
+LL |       let _: () = Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(O...
+   |  ____________--___^
+   | |            |
+   | |            expected due to this
+LL | |         Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(...
+LL | |             Ok(Ok(Ok(Ok(Ok(Ok(Ok("")))))))
+LL | |         ))))))))))))))))))))))))))))))
+LL | |     ))))))))))))))))))))))));
+   | |____________________________^ expected `()`, found enum `Result`
+   |
+   = note: expected unit type `()`
+                   found enum `Result<Result<..., ...>, ...>`
+           the full type name has been written to '$TEST_BUILD_DIR/diagnostic-width/long-E0308/long-E0308.long-type-hash.txt'
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
index d27b05fe7f7df721b5a41733fc2f7cbf6e49ec87..7229b9ac986ac73df2909af829ff3fb6d0d5730e 100644 (file)
@@ -12,10 +12,6 @@ LL |     Foo::<i32>::bar(&1i8);
              <i8 as Foo<u32>>
              <i8 as Foo<u64>>
              <i8 as Foo<u8>>
-             <u8 as Foo<bool>>
-             <u8 as Foo<u16>>
-             <u8 as Foo<u32>>
-             <u8 as Foo<u64>>
 
 error[E0277]: the trait bound `u8: Foo<i32>` is not satisfied
   --> $DIR/issue-39802-show-5-trait-impls.rs:25:21
@@ -26,11 +22,6 @@ LL |     Foo::<i32>::bar(&1u8);
    |     required by a bound introduced by this call
    |
    = help: the following other types implement trait `Foo<B>`:
-             <i8 as Foo<bool>>
-             <i8 as Foo<u16>>
-             <i8 as Foo<u32>>
-             <i8 as Foo<u64>>
-             <i8 as Foo<u8>>
              <u8 as Foo<bool>>
              <u8 as Foo<u16>>
              <u8 as Foo<u32>>
index 42925cfed5507f2ec6cc2e3b8fa4dc79eb20003d..87560c4c79735a9d83508be7d61b2e77a40c7893 100644 (file)
@@ -2,7 +2,7 @@ error[E0308]: mismatched types
   --> $DIR/disambiguate-identical-names.rs:13:10
    |
 LL |     test(&v);
-   |     ---- ^^ expected struct `std::vec::Vec`, found struct `HashMap`
+   |     ---- ^^ expected struct `Vec`, found struct `HashMap`
    |     |
    |     arguments to this function are incorrect
    |
index 42385216ae7656d1f135c0a33013b7ab451180ad..5ce1fd54a9e62027a7f53517d8fb03fb74c14207 100644 (file)
@@ -43,7 +43,7 @@ fn if_(&self) {
         }
 
         if {
-            if self.option_loud_drop(7).is_some() && self.option_loud_drop(6).is_some() {
+            if self.option_loud_drop(6).is_some() && self.option_loud_drop(7).is_some() {
                 self.loud_drop(8);
                 true
             } else {
@@ -118,17 +118,85 @@ fn match_(&self) {
         }
     }
 
+    fn and_chain(&self) {
+        // issue-103107
+        if self.option_loud_drop(1).is_some() // 1
+            && self.option_loud_drop(2).is_some() // 2
+            && self.option_loud_drop(3).is_some() // 3
+            && self.option_loud_drop(4).is_some() // 4
+            && self.option_loud_drop(5).is_some() // 5
+        {
+            self.print(6); // 6
+        }
+
+        let _ = self.option_loud_drop(7).is_some() // 1
+            && self.option_loud_drop(8).is_some() // 2
+            && self.option_loud_drop(9).is_some(); // 3
+        self.print(10); // 4
+
+        // Test associativity
+        if self.option_loud_drop(11).is_some() // 1
+            && (self.option_loud_drop(12).is_some() // 2
+            && self.option_loud_drop(13).is_some() // 3
+            && self.option_loud_drop(14).is_some()) // 4
+            && self.option_loud_drop(15).is_some() // 5
+        {
+            self.print(16); // 6
+        }
+    }
+
+    fn or_chain(&self) {
+        // issue-103107
+        if self.option_loud_drop(1).is_none() // 1
+            || self.option_loud_drop(2).is_none() // 2
+            || self.option_loud_drop(3).is_none() // 3
+            || self.option_loud_drop(4).is_none() // 4
+            || self.option_loud_drop(5).is_some() // 5
+        {
+            self.print(6); // 6
+        }
+
+        let _ = self.option_loud_drop(7).is_none() // 1
+            || self.option_loud_drop(8).is_none() // 2
+            || self.option_loud_drop(9).is_none(); // 3
+        self.print(10); // 4
+
+        // Test associativity
+        if self.option_loud_drop(11).is_none() // 1
+            || (self.option_loud_drop(12).is_none() // 2
+            || self.option_loud_drop(13).is_none() // 3
+            || self.option_loud_drop(14).is_none()) // 4
+            || self.option_loud_drop(15).is_some() // 5
+        {
+            self.print(16); // 6
+        }
+    }
+
+    fn mixed_and_or_chain(&self) {
+        // issue-103107
+        if self.option_loud_drop(1).is_none() // 1
+            || self.option_loud_drop(2).is_none() // 2
+            || self.option_loud_drop(3).is_some() // 3
+            && self.option_loud_drop(4).is_some() // 4
+            && self.option_loud_drop(5).is_none() // 5
+            || self.option_loud_drop(6).is_none() // 6
+            || self.option_loud_drop(7).is_some() // 7
+        {
+            self.print(8); // 8
+        }
+    }
+
     fn let_chain(&self) {
         // take the "then" branch
-        if self.option_loud_drop(2).is_some() // 2
-            && self.option_loud_drop(1).is_some() // 1
+        if self.option_loud_drop(1).is_some() // 1
+            && self.option_loud_drop(2).is_some() // 2
             && let Some(_d) = self.option_loud_drop(4) { // 4
             self.print(3); // 3
         }
 
         // take the "else" branch
-        if self.option_loud_drop(6).is_some() // 2
-            && self.option_loud_drop(5).is_some() // 1
+        if self.option_loud_drop(5).is_some() // 1
+            && self.option_loud_drop(6).is_some() // 2
             && let None = self.option_loud_drop(8) { // 4
             unreachable!();
         } else {
@@ -152,8 +220,8 @@ fn let_chain(&self) {
             }
 
         // let exprs last
-        if self.option_loud_drop(20).is_some() // 2
-            && self.option_loud_drop(19).is_some() // 1
+        if self.option_loud_drop(19).is_some() // 1
+            && self.option_loud_drop(20).is_some() // 2
             && let Some(_d) = self.option_loud_drop(23) // 5
             && let Some(_e) = self.option_loud_drop(22) { // 4
                 self.print(21); // 3
@@ -187,6 +255,21 @@ fn main() {
     collector.if_();
     collector.assert_sorted();
 
+    println!("-- and chain --");
+    let collector = DropOrderCollector::default();
+    collector.and_chain();
+    collector.assert_sorted();
+
+    println!("-- or chain --");
+    let collector = DropOrderCollector::default();
+    collector.or_chain();
+    collector.assert_sorted();
+
+    println!("-- mixed and/or chain --");
+    let collector = DropOrderCollector::default();
+    collector.mixed_and_or_chain();
+    collector.assert_sorted();
+
     println!("-- if let --");
     let collector = DropOrderCollector::default();
     collector.if_let();
diff --git a/src/test/ui/drop/issue-103107.rs b/src/test/ui/drop/issue-103107.rs
new file mode 100644 (file)
index 0000000..5f44759
--- /dev/null
@@ -0,0 +1,37 @@
+// check-pass
+// compile-flags: -Z validate-mir
+
+struct Foo<'a>(&'a mut u32);
+
+impl<'a> Drop for Foo<'a> {
+    fn drop(&mut self) {
+        *self.0 = 0;
+    }
+}
+
+fn and() {
+    let mut foo = 0;
+    // This used to compile also before the fix
+    if true && *Foo(&mut foo).0 == 0 && ({ foo = 0; true}) {}
+
+    // This used to fail before the fix
+    if *Foo(&mut foo).0 == 0 && ({ foo = 0; true}) {}
+
+    println!("{foo}");
+}
+
+fn or() {
+    let mut foo = 0;
+    // This used to compile also before the fix
+    if false || *Foo(&mut foo).0 == 1 || ({ foo = 0; true}) {}
+
+    // This used to fail before the fix
+    if *Foo(&mut foo).0 == 1 || ({ foo = 0; true}) {}
+
+    println!("{foo}");
+}
+
+fn main() {
+    and();
+    or();
+}
index 6754574f0b953673bbe7034498d4d5445f5e6b67..628f898d5c8790a7232b6dc43a184386dbc4dad5 100644 (file)
@@ -55,10 +55,10 @@ LL | impl<T,T> Qux<T,T> for Option<T> {}
    |      first use of `T`
 
 error[E0207]: the type parameter `T` is not constrained by the impl trait, self type, or predicates
-  --> $DIR/duplicate-type-parameter.rs:24:6
+  --> $DIR/duplicate-type-parameter.rs:24:8
    |
 LL | impl<T,T> Qux<T,T> for Option<T> {}
-   |      ^ unconstrained type parameter
+   |        ^ unconstrained type parameter
 
 error: aborting due to 8 previous errors
 
index e7c5918629bdc35f71dca040e4138e2af5270043..a3f4d21ca94bd882f67d9fd074e2ecbf9fac18bb 100644 (file)
@@ -2,7 +2,7 @@ error[E0308]: mismatched types
   --> $DIR/no-implicit-dyn-star.rs:6:48
    |
 LL |     dyn_star_foreign::require_dyn_star_display(1usize);
-   |     ------------------------------------------ ^^^^^^ expected trait object `dyn std::fmt::Display`, found `usize`
+   |     ------------------------------------------ ^^^^^^ expected trait object `dyn Display`, found `usize`
    |     |
    |     arguments to this function are incorrect
    |
diff --git a/src/test/ui/enum-discriminant/issue-104519.rs b/src/test/ui/enum-discriminant/issue-104519.rs
new file mode 100644 (file)
index 0000000..c4630f7
--- /dev/null
@@ -0,0 +1,36 @@
+// run-pass
+#![allow(dead_code)]
+
+enum OpenResult {
+    Ok(()),
+    Err(()),
+    TransportErr(TransportErr),
+}
+
+#[repr(i32)]
+enum TransportErr {
+    UnknownMethod = -2,
+}
+
+#[inline(never)]
+fn some_match(result: OpenResult) -> u8 {
+    match result {
+        OpenResult::Ok(()) => 0,
+        _ => 1,
+    }
+}
+
+fn main() {
+    let result = OpenResult::Ok(());
+    assert_eq!(some_match(result), 0);
+
+    let result = OpenResult::Ok(());
+    match result {
+        OpenResult::Ok(()) => (),
+        _ => unreachable!("message a"),
+    }
+    match result {
+        OpenResult::Ok(()) => (),
+        _ => unreachable!("message b"),
+    }
+}
index e5044468da12929266ca65867b6911295d6622fb..2eb123b7328dafde8d7a46c39bf6dce264e4ec8f 100644 (file)
@@ -1,7 +1,7 @@
 #![feature(type_ascription)]
 
 enum Bug<S> { //~ ERROR parameter `S` is never used
-    Var = 0: S,
+    Var = type_ascribe!(0, S),
     //~^ ERROR generic parameters may not be used
 }
 
index 4f5e236a37b45ec92dff46f15b621f067ae0b2ff..63d3521afe4fb598006b35d75f70f3e34030f459 100644 (file)
@@ -1,8 +1,8 @@
 error: generic parameters may not be used in const operations
-  --> $DIR/issue-67945-2.rs:4:14
+  --> $DIR/issue-67945-2.rs:4:28
    |
-LL |     Var = 0: S,
-   |              ^ cannot perform const operation using `S`
+LL |     Var = type_ascribe!(0, S),
+   |                            ^ cannot perform const operation using `S`
    |
    = note: type parameters may not be used in const expressions
    = help: use `#![feature(generic_const_exprs)]` to allow generic const expressions
index 49a4d984af9eb6143418ea31f0bf55e6f02fc9e7..451a683ac8a6effeec6de3067304913763e77885 100644 (file)
@@ -5,7 +5,7 @@ LL | impl<T> Foo for T where Bar<T>: Foo {}
    |                                 ^^^
    |
    = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`E0275`)
-note: required for `Bar<Bar<Bar<Bar<Bar<Bar<...>>>>>>` to implement `Foo`
+note: required for `Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<...>>>>>>>>>>>>>>>>>>>>>` to implement `Foo`
   --> $DIR/E0275.rs:6:9
    |
 LL | impl<T> Foo for T where Bar<T>: Foo {}
index c485bc5c3ab908db36abe89bbd0ba364828cb2c5..760dcb615c87903d522d89eb322e47139b919b82 100644 (file)
@@ -3,12 +3,18 @@ error[E0562]: `impl Trait` only allowed in function and inherent method return t
    |
 LL | fn f() -> impl Fn() -> impl Sized { || () }
    |                        ^^^^^^^^^^
+   |
+   = note: see issue #99697 <https://github.com/rust-lang/rust/issues/99697> for more information
+   = help: add `#![feature(impl_trait_in_fn_trait_return)]` to the crate attributes to enable
 
 error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in `Fn` trait return
   --> $DIR/feature-gate-impl_trait_in_fn_trait_return.rs:3:32
    |
 LL | fn g() -> &'static dyn Fn() -> impl Sized { &|| () }
    |                                ^^^^^^^^^^
+   |
+   = note: see issue #99697 <https://github.com/rust-lang/rust/issues/99697> for more information
+   = help: add `#![feature(impl_trait_in_fn_trait_return)]` to the crate attributes to enable
 
 error: aborting due to 2 previous errors
 
index 15b8d442aeb9a79a7017a0e4a63ad5633a7463ce..505f31ec6388d1d2bf4ce3a8b50ab77206527412 100644 (file)
@@ -1,5 +1,5 @@
 extern "C" {
-    #[linkage = "extern_weak"] static foo: isize;
+    #[linkage = "extern_weak"] static foo: *mut isize;
     //~^ ERROR: the `linkage` attribute is experimental and not portable
 }
 
index 3e5b79bfd417687e110bcc4dac046f347beb722e..a1c73e555ef7a35689004863f8bdf29cfc38d3ed 100644 (file)
@@ -1,7 +1,7 @@
 error[E0658]: the `linkage` attribute is experimental and not portable across platforms
   --> $DIR/feature-gate-linkage.rs:2:5
    |
-LL |     #[linkage = "extern_weak"] static foo: isize;
+LL |     #[linkage = "extern_weak"] static foo: *mut isize;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: see issue #29603 <https://github.com/rust-lang/rust/issues/29603> for more information
diff --git a/src/test/ui/fn/signature-error-reporting-under-verbose.rs b/src/test/ui/fn/signature-error-reporting-under-verbose.rs
new file mode 100644 (file)
index 0000000..d7a8c95
--- /dev/null
@@ -0,0 +1,15 @@
+// compile-flags: -Zverbose
+
+fn foo(_: i32, _: i32) {}
+
+fn needs_ptr(_: fn(i32, u32)) {}
+//~^ NOTE function defined here
+//~| NOTE
+
+fn main() {
+    needs_ptr(foo);
+    //~^ ERROR mismatched types
+    //~| NOTE expected `u32`, found `i32`
+    //~| NOTE expected fn pointer `fn(i32, u32)`
+    //~| NOTE arguments to this function are incorrect
+}
diff --git a/src/test/ui/fn/signature-error-reporting-under-verbose.stderr b/src/test/ui/fn/signature-error-reporting-under-verbose.stderr
new file mode 100644 (file)
index 0000000..6260fc8
--- /dev/null
@@ -0,0 +1,19 @@
+error[E0308]: mismatched types
+  --> $DIR/signature-error-reporting-under-verbose.rs:10:15
+   |
+LL |     needs_ptr(foo);
+   |     --------- ^^^ expected `u32`, found `i32`
+   |     |
+   |     arguments to this function are incorrect
+   |
+   = note: expected fn pointer `fn(i32, u32)`
+                 found fn item `fn(i32, i32) {foo}`
+note: function defined here
+  --> $DIR/signature-error-reporting-under-verbose.rs:5:4
+   |
+LL | fn needs_ptr(_: fn(i32, u32)) {}
+   |    ^^^^^^^^^ ---------------
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
index 2e02078048027732a86e45f7d2adfa1faaa36948..ed0628bbbc3cce135ed9308d8911b9aa66e14fff 100644 (file)
@@ -9,7 +9,7 @@ note: generator is not `Send` as this value is used across a yield
   --> $DIR/generator-print-verbose-1.rs:35:9
    |
 LL |         let _non_send_gen = make_non_send_generator();
-   |             ------------- has type `Opaque(DefId(0:44 ~ generator_print_verbose_1[749a]::make_non_send_generator::{opaque#0}), [])` which is not `Send`
+   |             ------------- has type `Opaque(DefId(0:34 ~ generator_print_verbose_1[749a]::make_non_send_generator::{opaque#0}), [])` which is not `Send`
 LL |         yield;
    |         ^^^^^ yield occurs here, with `_non_send_gen` maybe used later
 LL |     };
@@ -35,17 +35,17 @@ note: required because it's used within this generator
    |
 LL |     || {
    |     ^^
-note: required because it appears within the type `Opaque(DefId(0:45 ~ generator_print_verbose_1[749a]::make_gen2::{opaque#0}), [std::sync::Arc<std::cell::RefCell<i32>>])`
+note: required because it appears within the type `Opaque(DefId(0:35 ~ generator_print_verbose_1[749a]::make_gen2::{opaque#0}), [std::sync::Arc<std::cell::RefCell<i32>>])`
   --> $DIR/generator-print-verbose-1.rs:41:30
    |
 LL | pub fn make_gen2<T>(t: T) -> impl Generator<Return = T> {
    |                              ^^^^^^^^^^^^^^^^^^^^^^^^^^
-note: required because it appears within the type `Opaque(DefId(0:46 ~ generator_print_verbose_1[749a]::make_non_send_generator2::{opaque#0}), [])`
+note: required because it appears within the type `Opaque(DefId(0:36 ~ generator_print_verbose_1[749a]::make_non_send_generator2::{opaque#0}), [])`
   --> $DIR/generator-print-verbose-1.rs:47:34
    |
 LL | fn make_non_send_generator2() -> impl Generator<Return = Arc<RefCell<i32>>> {
    |                                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   = note: required because it captures the following types: `Opaque(DefId(0:46 ~ generator_print_verbose_1[749a]::make_non_send_generator2::{opaque#0}), [])`, `()`
+   = note: required because it captures the following types: `Opaque(DefId(0:36 ~ generator_print_verbose_1[749a]::make_non_send_generator2::{opaque#0}), [])`, `()`
 note: required because it's used within this generator
   --> $DIR/generator-print-verbose-1.rs:52:20
    |
index c81cd7e7718ca86f85392142b68bbbde3f5698ae..83ee04d5a6c600c1b66be81974620cbf4545b219 100644 (file)
@@ -8,7 +8,7 @@ note: required by a bound in `foo_defn::Foo::Bar`
   --> $DIR/auxiliary/foo_defn.rs:4:15
    |
 LL |     type Bar: AsRef<()>;
-   |               ^^^^^^^^^ required by this bound in `foo_defn::Foo::Bar`
+   |               ^^^^^^^^^ required by this bound in `Foo::Bar`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/generic-associated-types/own-bound-span.rs b/src/test/ui/generic-associated-types/own-bound-span.rs
new file mode 100644 (file)
index 0000000..3699f72
--- /dev/null
@@ -0,0 +1,17 @@
+struct S;
+
+trait D {
+    type P<T: Copy>;
+    //~^ NOTE required by this bound in `D::P`
+    //~| NOTE required by a bound in `D::P`
+}
+
+impl D for S {
+    type P<T: Copy> = ();
+}
+
+fn main() {
+    let _: <S as D>::P<String>;
+    //~^ ERROR the trait bound `String: Copy` is not satisfied
+    //~| NOTE the trait `Copy` is not implemented for `String`
+}
diff --git a/src/test/ui/generic-associated-types/own-bound-span.stderr b/src/test/ui/generic-associated-types/own-bound-span.stderr
new file mode 100644 (file)
index 0000000..8ab8ea6
--- /dev/null
@@ -0,0 +1,15 @@
+error[E0277]: the trait bound `String: Copy` is not satisfied
+  --> $DIR/own-bound-span.rs:14:12
+   |
+LL |     let _: <S as D>::P<String>;
+   |            ^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `String`
+   |
+note: required by a bound in `D::P`
+  --> $DIR/own-bound-span.rs:4:15
+   |
+LL |     type P<T: Copy>;
+   |               ^^^^ required by this bound in `D::P`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
index 58172bf06b512e6ff1ff42ca4070443e992913ce..9e9b2e18abeb85164e1cdbd2f2ef09204bd456de 100644 (file)
@@ -108,17 +108,6 @@ LL |     type Bar<'b>;
    = note: this bound is currently required to ensure that impls have maximum flexibility
    = note: we are soliciting feedback, see issue #87479 <https://github.com/rust-lang/rust/issues/87479> for more information
 
-error: missing required bound on `Item`
-  --> $DIR/self-outlives-lint.rs:140:5
-   |
-LL |     type Item<'a>;
-   |     ^^^^^^^^^^^^^-
-   |                  |
-   |                  help: add the required where clause: `where Self: 'a`
-   |
-   = note: this bound is currently required to ensure that impls have maximum flexibility
-   = note: we are soliciting feedback, see issue #87479 <https://github.com/rust-lang/rust/issues/87479> for more information
-
 error: missing required bound on `Iterator`
   --> $DIR/self-outlives-lint.rs:142:5
    |
@@ -130,6 +119,17 @@ LL |     type Iterator<'a>: Iterator<Item = Self::Item<'a>>;
    = note: this bound is currently required to ensure that impls have maximum flexibility
    = note: we are soliciting feedback, see issue #87479 <https://github.com/rust-lang/rust/issues/87479> for more information
 
+error: missing required bound on `Item`
+  --> $DIR/self-outlives-lint.rs:140:5
+   |
+LL |     type Item<'a>;
+   |     ^^^^^^^^^^^^^-
+   |                  |
+   |                  help: add the required where clause: `where Self: 'a`
+   |
+   = note: this bound is currently required to ensure that impls have maximum flexibility
+   = note: we are soliciting feedback, see issue #87479 <https://github.com/rust-lang/rust/issues/87479> for more information
+
 error: missing required bound on `Item`
   --> $DIR/self-outlives-lint.rs:148:5
    |
index a6f8563a047851e8a0ea337d02ca329895a881d5..095a1c6af37bcb5eb5946dbab8120bd91e4bca45 100644 (file)
@@ -4,7 +4,7 @@ error[E0308]: mismatched types
 LL |     match [5..4, 99..105, 43..44] {
    |           ----------------------- this expression has type `[std::ops::Range<{integer}>; 3]`
 LL |         [_, 99.., _] => {},
-   |             ^^ expected struct `std::ops::Range`, found integer
+   |             ^^ expected struct `Range`, found integer
    |
    = note: expected struct `std::ops::Range<{integer}>`
                 found type `{integer}`
index 4e0102c930da82b7ab86b7bac25a73033f2fe8f6..2ea3205dcd4acef72ba300757f41be06c3f0f11b 100644 (file)
@@ -10,7 +10,7 @@ error[E0308]: mismatched types
 LL |     match [5..4, 99..105, 43..44] {
    |           ----------------------- this expression has type `[std::ops::Range<{integer}>; 3]`
 LL |         [_, 99..] => {},
-   |             ^^ expected struct `std::ops::Range`, found integer
+   |             ^^ expected struct `Range`, found integer
    |
    = note: expected struct `std::ops::Range<{integer}>`
                 found type `{integer}`
index 790a1337228d00eaab73825e8d7968032866a4b2..bbdf0c83f6203f073c9ba9f9876b239a5be4924a 100644 (file)
@@ -4,7 +4,7 @@ error[E0308]: mismatched types
 LL |     match [5..4, 99..105, 43..44] {
    |           ----------------------- this expression has type `[std::ops::Range<{integer}>; 3]`
 LL |         [..9, 99..100, _] => {},
-   |            ^ expected struct `std::ops::Range`, found integer
+   |            ^ expected struct `Range`, found integer
    |
    = note: expected struct `std::ops::Range<{integer}>`
                 found type `{integer}`
@@ -17,7 +17,7 @@ LL |     match [5..4, 99..105, 43..44] {
 LL |         [..9, 99..100, _] => {},
    |               ^^  --- this is of type `{integer}`
    |               |
-   |               expected struct `std::ops::Range`, found integer
+   |               expected struct `Range`, found integer
    |
    = note: expected struct `std::ops::Range<{integer}>`
                 found type `{integer}`
@@ -28,7 +28,7 @@ error[E0308]: mismatched types
 LL |     match [5..4, 99..105, 43..44] {
    |           ----------------------- this expression has type `[std::ops::Range<{integer}>; 3]`
 LL |         [..9, 99..100, _] => {},
-   |               --  ^^^ expected struct `std::ops::Range`, found integer
+   |               --  ^^^ expected struct `Range`, found integer
    |               |
    |               this is of type `{integer}`
    |
index 1841b8e5dcd0849d7d659594f5081fc21a661279..69f4cbbbf429496a67df930d0bdd32a1a27e07f5 100644 (file)
@@ -30,15 +30,10 @@ LL |         n + sum_to(n - 1)
    |
    = help: the trait `Add<impl Foo>` is not implemented for `u32`
    = 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
+             <&'a u32 as Add<u32>>
+             <&u32 as Add<&u32>>
+             <u32 as Add<&u32>>
+             <u32 as Add>
 
 error: aborting due to 2 previous errors; 1 warning emitted
 
diff --git a/src/test/ui/impl-trait/in-trait/where-clause.rs b/src/test/ui/impl-trait/in-trait/where-clause.rs
new file mode 100644 (file)
index 0000000..87bac51
--- /dev/null
@@ -0,0 +1,24 @@
+// check-pass
+// edition: 2021
+
+#![feature(return_position_impl_trait_in_trait)]
+#![allow(incomplete_features)]
+
+use std::fmt::Debug;
+
+trait Foo<Item> {
+    fn foo<'a>(&'a self) -> impl Debug
+    where
+        Item: 'a;
+}
+
+impl<Item, D: Debug + Clone> Foo<Item> for D {
+    fn foo<'a>(&'a self) -> impl Debug
+    where
+        Item: 'a,
+    {
+        self.clone()
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/impl-trait/nested-return-type4.rs b/src/test/ui/impl-trait/nested-return-type4.rs
new file mode 100644 (file)
index 0000000..cec70bb
--- /dev/null
@@ -0,0 +1,8 @@
+// edition: 2021
+
+fn test<'s: 's>(s: &'s str) -> impl std::future::Future<Output = impl Sized> {
+    async move { let _s = s; }
+    //~^ ERROR hidden type for `impl Future<Output = impl Sized>` captures lifetime that does not appear in bounds
+}
+
+fn main() {}
diff --git a/src/test/ui/impl-trait/nested-return-type4.stderr b/src/test/ui/impl-trait/nested-return-type4.stderr
new file mode 100644 (file)
index 0000000..e761a60
--- /dev/null
@@ -0,0 +1,20 @@
+error[E0700]: hidden type for `impl Future<Output = impl Sized>` captures lifetime that does not appear in bounds
+  --> $DIR/nested-return-type4.rs:4:5
+   |
+LL | fn test<'s: 's>(s: &'s str) -> impl std::future::Future<Output = impl Sized> {
+   |         -- hidden type `[async block@$DIR/nested-return-type4.rs:4:5: 4:31]` captures the lifetime `'s` as defined here
+LL |     async move { let _s = s; }
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: to declare that `impl Future<Output = impl Sized>` captures `'s`, you can add an explicit `'s` lifetime bound
+   |
+LL | fn test<'s: 's>(s: &'s str) -> impl std::future::Future<Output = impl Sized> + 's {
+   |                                                                              ++++
+help: to declare that `impl Sized` captures `'s`, you can add an explicit `'s` lifetime bound
+   |
+LL | fn test<'s: 's>(s: &'s str) -> impl std::future::Future<Output = impl Sized + 's> {
+   |                                                                             ++++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0700`.
index 3dda5761ada6b34a97ef22bab914c84611f369cf..3ee26f74a787be7424d2f48ad65f0be1e8fb4260 100644 (file)
@@ -15,7 +15,7 @@ LL |     type Foo = impl PartialEq<(Foo, i32)>;
 LL |         fn eq(&self, _other: &(Foo, i32)) -> bool {
    |                              ^^^^^^^^^^^
    |                              |
-   |                              expected struct `a::Bar`, found opaque type
+   |                              expected struct `Bar`, found opaque type
    |                              help: change the parameter type to match the trait: `&(a::Bar, i32)`
    |
    = note: expected fn pointer `fn(&a::Bar, &(a::Bar, i32)) -> _`
@@ -38,7 +38,7 @@ LL |     type Foo = impl PartialEq<(Foo, i32)>;
 LL |         fn eq(&self, _other: &(Bar, i32)) -> bool {
    |                              ^^^^^^^^^^^
    |                              |
-   |                              expected opaque type, found struct `b::Bar`
+   |                              expected opaque type, found struct `Bar`
    |                              help: change the parameter type to match the trait: `&(b::Foo, i32)`
    |
    = note: expected fn pointer `fn(&b::Bar, &(b::Foo, i32)) -> _`
index 034005697b4343b239e27871028732a1f068c5aa..3db67cdb5370a154642161edc43cd646195c4c84 100644 (file)
@@ -87,7 +87,10 @@ error[E0308]: mismatched types
   --> $DIR/deref-suggestion.rs:37:5
    |
 LL |     assert_eq!(3i32, &3i32);
-   |     ^^^^^^^^^^^^^^^^^^^^^^^ expected `i32`, found `&i32`
+   |     ^^^^^^^^^^^^^^^^^^^^^^^
+   |     |
+   |     expected `i32`, found `&i32`
+   |     expected because this is `i32`
    |
    = note: this error originates in the macro `assert_eq` (in Nightly builds, run with -Z macro-backtrace for more info)
 
index 620c9e110ff6822b9d71151805beca0c365aae53..53b603a47b5516a7d2f6800ed980e593c16bbf0f 100644 (file)
@@ -2,143 +2,648 @@ error[E0080]: evaluation of constant value failed
   --> $DIR/infinite-recursion-const-fn.rs:4:5
    |
 LL |     b()
+   |     ^^^ reached the configured maximum number of stack frames
+   |
+note: inside `a`
+  --> $DIR/infinite-recursion-const-fn.rs:4:5
+   |
+LL |     b()
+   |     ^^^
+note: inside `b`
+  --> $DIR/infinite-recursion-const-fn.rs:7:5
+   |
+LL |     a()
+   |     ^^^
+note: inside `a`
+  --> $DIR/infinite-recursion-const-fn.rs:4:5
+   |
+LL |     b()
+   |     ^^^
+note: inside `b`
+  --> $DIR/infinite-recursion-const-fn.rs:7:5
+   |
+LL |     a()
+   |     ^^^
+note: inside `a`
+  --> $DIR/infinite-recursion-const-fn.rs:4:5
+   |
+LL |     b()
+   |     ^^^
+note: inside `b`
+  --> $DIR/infinite-recursion-const-fn.rs:7:5
+   |
+LL |     a()
+   |     ^^^
+note: inside `a`
+  --> $DIR/infinite-recursion-const-fn.rs:4:5
+   |
+LL |     b()
+   |     ^^^
+note: inside `b`
+  --> $DIR/infinite-recursion-const-fn.rs:7:5
+   |
+LL |     a()
+   |     ^^^
+note: inside `a`
+  --> $DIR/infinite-recursion-const-fn.rs:4:5
+   |
+LL |     b()
+   |     ^^^
+note: inside `b`
+  --> $DIR/infinite-recursion-const-fn.rs:7:5
+   |
+LL |     a()
+   |     ^^^
+note: inside `a`
+  --> $DIR/infinite-recursion-const-fn.rs:4:5
+   |
+LL |     b()
+   |     ^^^
+note: inside `b`
+  --> $DIR/infinite-recursion-const-fn.rs:7:5
+   |
+LL |     a()
+   |     ^^^
+note: inside `a`
+  --> $DIR/infinite-recursion-const-fn.rs:4:5
+   |
+LL |     b()
+   |     ^^^
+note: inside `b`
+  --> $DIR/infinite-recursion-const-fn.rs:7:5
+   |
+LL |     a()
+   |     ^^^
+note: inside `a`
+  --> $DIR/infinite-recursion-const-fn.rs:4:5
+   |
+LL |     b()
+   |     ^^^
+note: inside `b`
+  --> $DIR/infinite-recursion-const-fn.rs:7:5
+   |
+LL |     a()
+   |     ^^^
+note: inside `a`
+  --> $DIR/infinite-recursion-const-fn.rs:4:5
+   |
+LL |     b()
+   |     ^^^
+note: inside `b`
+  --> $DIR/infinite-recursion-const-fn.rs:7:5
+   |
+LL |     a()
+   |     ^^^
+note: inside `a`
+  --> $DIR/infinite-recursion-const-fn.rs:4:5
+   |
+LL |     b()
+   |     ^^^
+note: inside `b`
+  --> $DIR/infinite-recursion-const-fn.rs:7:5
+   |
+LL |     a()
+   |     ^^^
+note: inside `a`
+  --> $DIR/infinite-recursion-const-fn.rs:4:5
+   |
+LL |     b()
+   |     ^^^
+note: inside `b`
+  --> $DIR/infinite-recursion-const-fn.rs:7:5
+   |
+LL |     a()
+   |     ^^^
+note: inside `a`
+  --> $DIR/infinite-recursion-const-fn.rs:4:5
+   |
+LL |     b()
+   |     ^^^
+note: inside `b`
+  --> $DIR/infinite-recursion-const-fn.rs:7:5
+   |
+LL |     a()
+   |     ^^^
+note: inside `a`
+  --> $DIR/infinite-recursion-const-fn.rs:4:5
+   |
+LL |     b()
+   |     ^^^
+note: inside `b`
+  --> $DIR/infinite-recursion-const-fn.rs:7:5
+   |
+LL |     a()
+   |     ^^^
+note: inside `a`
+  --> $DIR/infinite-recursion-const-fn.rs:4:5
+   |
+LL |     b()
+   |     ^^^
+note: inside `b`
+  --> $DIR/infinite-recursion-const-fn.rs:7:5
+   |
+LL |     a()
+   |     ^^^
+note: inside `a`
+  --> $DIR/infinite-recursion-const-fn.rs:4:5
+   |
+LL |     b()
+   |     ^^^
+note: inside `b`
+  --> $DIR/infinite-recursion-const-fn.rs:7:5
+   |
+LL |     a()
+   |     ^^^
+note: inside `a`
+  --> $DIR/infinite-recursion-const-fn.rs:4:5
+   |
+LL |     b()
+   |     ^^^
+note: inside `b`
+  --> $DIR/infinite-recursion-const-fn.rs:7:5
+   |
+LL |     a()
+   |     ^^^
+note: inside `a`
+  --> $DIR/infinite-recursion-const-fn.rs:4:5
+   |
+LL |     b()
+   |     ^^^
+note: inside `b`
+  --> $DIR/infinite-recursion-const-fn.rs:7:5
+   |
+LL |     a()
+   |     ^^^
+note: inside `a`
+  --> $DIR/infinite-recursion-const-fn.rs:4:5
+   |
+LL |     b()
+   |     ^^^
+note: inside `b`
+  --> $DIR/infinite-recursion-const-fn.rs:7:5
+   |
+LL |     a()
+   |     ^^^
+note: inside `a`
+  --> $DIR/infinite-recursion-const-fn.rs:4:5
+   |
+LL |     b()
+   |     ^^^
+note: inside `b`
+  --> $DIR/infinite-recursion-const-fn.rs:7:5
+   |
+LL |     a()
+   |     ^^^
+note: inside `a`
+  --> $DIR/infinite-recursion-const-fn.rs:4:5
+   |
+LL |     b()
+   |     ^^^
+note: inside `b`
+  --> $DIR/infinite-recursion-const-fn.rs:7:5
+   |
+LL |     a()
+   |     ^^^
+note: inside `a`
+  --> $DIR/infinite-recursion-const-fn.rs:4:5
+   |
+LL |     b()
+   |     ^^^
+note: inside `b`
+  --> $DIR/infinite-recursion-const-fn.rs:7:5
+   |
+LL |     a()
+   |     ^^^
+note: inside `a`
+  --> $DIR/infinite-recursion-const-fn.rs:4:5
+   |
+LL |     b()
+   |     ^^^
+note: inside `b`
+  --> $DIR/infinite-recursion-const-fn.rs:7:5
+   |
+LL |     a()
+   |     ^^^
+note: inside `a`
+  --> $DIR/infinite-recursion-const-fn.rs:4:5
+   |
+LL |     b()
+   |     ^^^
+note: inside `b`
+  --> $DIR/infinite-recursion-const-fn.rs:7:5
+   |
+LL |     a()
+   |     ^^^
+note: inside `a`
+  --> $DIR/infinite-recursion-const-fn.rs:4:5
+   |
+LL |     b()
+   |     ^^^
+note: inside `b`
+  --> $DIR/infinite-recursion-const-fn.rs:7:5
+   |
+LL |     a()
+   |     ^^^
+note: inside `a`
+  --> $DIR/infinite-recursion-const-fn.rs:4:5
+   |
+LL |     b()
+   |     ^^^
+note: inside `b`
+  --> $DIR/infinite-recursion-const-fn.rs:7:5
+   |
+LL |     a()
+   |     ^^^
+note: inside `a`
+  --> $DIR/infinite-recursion-const-fn.rs:4:5
+   |
+LL |     b()
+   |     ^^^
+note: inside `b`
+  --> $DIR/infinite-recursion-const-fn.rs:7:5
+   |
+LL |     a()
+   |     ^^^
+note: inside `a`
+  --> $DIR/infinite-recursion-const-fn.rs:4:5
+   |
+LL |     b()
+   |     ^^^
+note: inside `b`
+  --> $DIR/infinite-recursion-const-fn.rs:7:5
+   |
+LL |     a()
+   |     ^^^
+note: inside `a`
+  --> $DIR/infinite-recursion-const-fn.rs:4:5
+   |
+LL |     b()
+   |     ^^^
+note: inside `b`
+  --> $DIR/infinite-recursion-const-fn.rs:7:5
+   |
+LL |     a()
+   |     ^^^
+note: inside `a`
+  --> $DIR/infinite-recursion-const-fn.rs:4:5
+   |
+LL |     b()
+   |     ^^^
+note: inside `b`
+  --> $DIR/infinite-recursion-const-fn.rs:7:5
+   |
+LL |     a()
+   |     ^^^
+note: inside `a`
+  --> $DIR/infinite-recursion-const-fn.rs:4:5
+   |
+LL |     b()
+   |     ^^^
+note: inside `b`
+  --> $DIR/infinite-recursion-const-fn.rs:7:5
+   |
+LL |     a()
+   |     ^^^
+note: inside `a`
+  --> $DIR/infinite-recursion-const-fn.rs:4:5
+   |
+LL |     b()
+   |     ^^^
+note: inside `b`
+  --> $DIR/infinite-recursion-const-fn.rs:7:5
+   |
+LL |     a()
+   |     ^^^
+note: inside `a`
+  --> $DIR/infinite-recursion-const-fn.rs:4:5
+   |
+LL |     b()
+   |     ^^^
+note: inside `b`
+  --> $DIR/infinite-recursion-const-fn.rs:7:5
+   |
+LL |     a()
+   |     ^^^
+note: inside `a`
+  --> $DIR/infinite-recursion-const-fn.rs:4:5
+   |
+LL |     b()
+   |     ^^^
+note: inside `b`
+  --> $DIR/infinite-recursion-const-fn.rs:7:5
+   |
+LL |     a()
+   |     ^^^
+note: inside `a`
+  --> $DIR/infinite-recursion-const-fn.rs:4:5
+   |
+LL |     b()
+   |     ^^^
+note: inside `b`
+  --> $DIR/infinite-recursion-const-fn.rs:7:5
+   |
+LL |     a()
+   |     ^^^
+note: inside `a`
+  --> $DIR/infinite-recursion-const-fn.rs:4:5
+   |
+LL |     b()
+   |     ^^^
+note: inside `b`
+  --> $DIR/infinite-recursion-const-fn.rs:7:5
+   |
+LL |     a()
+   |     ^^^
+note: inside `a`
+  --> $DIR/infinite-recursion-const-fn.rs:4:5
+   |
+LL |     b()
+   |     ^^^
+note: inside `b`
+  --> $DIR/infinite-recursion-const-fn.rs:7:5
+   |
+LL |     a()
+   |     ^^^
+note: inside `a`
+  --> $DIR/infinite-recursion-const-fn.rs:4:5
+   |
+LL |     b()
+   |     ^^^
+note: inside `b`
+  --> $DIR/infinite-recursion-const-fn.rs:7:5
+   |
+LL |     a()
+   |     ^^^
+note: inside `a`
+  --> $DIR/infinite-recursion-const-fn.rs:4:5
+   |
+LL |     b()
+   |     ^^^
+note: inside `b`
+  --> $DIR/infinite-recursion-const-fn.rs:7:5
+   |
+LL |     a()
+   |     ^^^
+note: inside `a`
+  --> $DIR/infinite-recursion-const-fn.rs:4:5
+   |
+LL |     b()
+   |     ^^^
+note: inside `b`
+  --> $DIR/infinite-recursion-const-fn.rs:7:5
+   |
+LL |     a()
+   |     ^^^
+note: inside `a`
+  --> $DIR/infinite-recursion-const-fn.rs:4:5
+   |
+LL |     b()
+   |     ^^^
+note: inside `b`
+  --> $DIR/infinite-recursion-const-fn.rs:7:5
+   |
+LL |     a()
+   |     ^^^
+note: inside `a`
+  --> $DIR/infinite-recursion-const-fn.rs:4:5
+   |
+LL |     b()
+   |     ^^^
+note: inside `b`
+  --> $DIR/infinite-recursion-const-fn.rs:7:5
+   |
+LL |     a()
+   |     ^^^
+note: inside `a`
+  --> $DIR/infinite-recursion-const-fn.rs:4:5
+   |
+LL |     b()
+   |     ^^^
+note: inside `b`
+  --> $DIR/infinite-recursion-const-fn.rs:7:5
+   |
+LL |     a()
+   |     ^^^
+note: inside `a`
+  --> $DIR/infinite-recursion-const-fn.rs:4:5
+   |
+LL |     b()
+   |     ^^^
+note: inside `b`
+  --> $DIR/infinite-recursion-const-fn.rs:7:5
+   |
+LL |     a()
+   |     ^^^
+note: inside `a`
+  --> $DIR/infinite-recursion-const-fn.rs:4:5
+   |
+LL |     b()
+   |     ^^^
+note: inside `b`
+  --> $DIR/infinite-recursion-const-fn.rs:7:5
+   |
+LL |     a()
+   |     ^^^
+note: inside `a`
+  --> $DIR/infinite-recursion-const-fn.rs:4:5
+   |
+LL |     b()
+   |     ^^^
+note: inside `b`
+  --> $DIR/infinite-recursion-const-fn.rs:7:5
+   |
+LL |     a()
+   |     ^^^
+note: inside `a`
+  --> $DIR/infinite-recursion-const-fn.rs:4:5
+   |
+LL |     b()
+   |     ^^^
+note: inside `b`
+  --> $DIR/infinite-recursion-const-fn.rs:7:5
+   |
+LL |     a()
+   |     ^^^
+note: inside `a`
+  --> $DIR/infinite-recursion-const-fn.rs:4:5
+   |
+LL |     b()
+   |     ^^^
+note: inside `b`
+  --> $DIR/infinite-recursion-const-fn.rs:7:5
+   |
+LL |     a()
    |     ^^^
-   |     |
-   |     reached the configured maximum number of stack frames
-   |     inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5
-   |     inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5
-   |     inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5
-   |     inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5
-   |     inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5
-   |     inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5
-   |     inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5
-   |     inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5
-   |     inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5
-   |     inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5
-   |     inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5
-   |     inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5
-   |     inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5
-   |     inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5
-   |     inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5
-   |     inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5
-   |     inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5
-   |     inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5
-   |     inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5
-   |     inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5
-   |     inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5
-   |     inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5
-   |     inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5
-   |     inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5
-   |     inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5
-   |     inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5
-   |     inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5
-   |     inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5
-   |     inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5
-   |     inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5
-   |     inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5
-   |     inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5
-   |     inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5
-   |     inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5
-   |     inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5
-   |     inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5
-   |     inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5
-   |     inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5
-   |     inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5
-   |     inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5
-   |     inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5
-   |     inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5
-   |     inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5
-   |     inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5
-   |     inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5
-   |     inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5
-   |     inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5
-   |     inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5
-   |     inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5
-   |     inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5
-   |     inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5
-   |     inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5
-   |     inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5
-   |     inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5
-   |     inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5
-   |     inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5
-   |     inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5
-   |     inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5
-   |     inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5
-   |     inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5
-   |     inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5
-   |     inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5
-   |     inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5
-   |     inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5
-...
-LL |     a()
-   |     ---
-   |     |
-   |     inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5
-   |     inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5
-   |     inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5
-   |     inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5
-   |     inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5
-   |     inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5
-   |     inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5
-   |     inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5
-   |     inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5
-   |     inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5
-   |     inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5
-   |     inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5
-   |     inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5
-   |     inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5
-   |     inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5
-   |     inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5
-   |     inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5
-   |     inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5
-   |     inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5
-   |     inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5
-   |     inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5
-   |     inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5
-   |     inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5
-   |     inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5
-   |     inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5
-   |     inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5
-   |     inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5
-   |     inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5
-   |     inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5
-   |     inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5
-   |     inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5
-   |     inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5
-   |     inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5
-   |     inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5
-   |     inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5
-   |     inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5
-   |     inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5
-   |     inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5
-   |     inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5
-   |     inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5
-   |     inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5
-   |     inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5
-   |     inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5
-   |     inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5
-   |     inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5
-   |     inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5
-   |     inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5
-   |     inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5
-   |     inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5
-   |     inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5
-   |     inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5
-   |     inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5
-   |     inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5
-   |     inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5
-   |     inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5
-   |     inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5
-   |     inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5
-   |     inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5
-   |     inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5
-   |     inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5
-   |     inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5
-   |     inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5
-   |     inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5
-LL | }
+note: inside `a`
+  --> $DIR/infinite-recursion-const-fn.rs:4:5
+   |
+LL |     b()
+   |     ^^^
+note: inside `b`
+  --> $DIR/infinite-recursion-const-fn.rs:7:5
+   |
+LL |     a()
+   |     ^^^
+note: inside `a`
+  --> $DIR/infinite-recursion-const-fn.rs:4:5
+   |
+LL |     b()
+   |     ^^^
+note: inside `b`
+  --> $DIR/infinite-recursion-const-fn.rs:7:5
+   |
+LL |     a()
+   |     ^^^
+note: inside `a`
+  --> $DIR/infinite-recursion-const-fn.rs:4:5
+   |
+LL |     b()
+   |     ^^^
+note: inside `b`
+  --> $DIR/infinite-recursion-const-fn.rs:7:5
+   |
+LL |     a()
+   |     ^^^
+note: inside `a`
+  --> $DIR/infinite-recursion-const-fn.rs:4:5
+   |
+LL |     b()
+   |     ^^^
+note: inside `b`
+  --> $DIR/infinite-recursion-const-fn.rs:7:5
+   |
+LL |     a()
+   |     ^^^
+note: inside `a`
+  --> $DIR/infinite-recursion-const-fn.rs:4:5
+   |
+LL |     b()
+   |     ^^^
+note: inside `b`
+  --> $DIR/infinite-recursion-const-fn.rs:7:5
+   |
+LL |     a()
+   |     ^^^
+note: inside `a`
+  --> $DIR/infinite-recursion-const-fn.rs:4:5
+   |
+LL |     b()
+   |     ^^^
+note: inside `b`
+  --> $DIR/infinite-recursion-const-fn.rs:7:5
+   |
+LL |     a()
+   |     ^^^
+note: inside `a`
+  --> $DIR/infinite-recursion-const-fn.rs:4:5
+   |
+LL |     b()
+   |     ^^^
+note: inside `b`
+  --> $DIR/infinite-recursion-const-fn.rs:7:5
+   |
+LL |     a()
+   |     ^^^
+note: inside `a`
+  --> $DIR/infinite-recursion-const-fn.rs:4:5
+   |
+LL |     b()
+   |     ^^^
+note: inside `b`
+  --> $DIR/infinite-recursion-const-fn.rs:7:5
+   |
+LL |     a()
+   |     ^^^
+note: inside `a`
+  --> $DIR/infinite-recursion-const-fn.rs:4:5
+   |
+LL |     b()
+   |     ^^^
+note: inside `b`
+  --> $DIR/infinite-recursion-const-fn.rs:7:5
+   |
+LL |     a()
+   |     ^^^
+note: inside `a`
+  --> $DIR/infinite-recursion-const-fn.rs:4:5
+   |
+LL |     b()
+   |     ^^^
+note: inside `b`
+  --> $DIR/infinite-recursion-const-fn.rs:7:5
+   |
+LL |     a()
+   |     ^^^
+note: inside `a`
+  --> $DIR/infinite-recursion-const-fn.rs:4:5
+   |
+LL |     b()
+   |     ^^^
+note: inside `b`
+  --> $DIR/infinite-recursion-const-fn.rs:7:5
+   |
+LL |     a()
+   |     ^^^
+note: inside `a`
+  --> $DIR/infinite-recursion-const-fn.rs:4:5
+   |
+LL |     b()
+   |     ^^^
+note: inside `b`
+  --> $DIR/infinite-recursion-const-fn.rs:7:5
+   |
+LL |     a()
+   |     ^^^
+note: inside `a`
+  --> $DIR/infinite-recursion-const-fn.rs:4:5
+   |
+LL |     b()
+   |     ^^^
+note: inside `b`
+  --> $DIR/infinite-recursion-const-fn.rs:7:5
+   |
+LL |     a()
+   |     ^^^
+note: inside `a`
+  --> $DIR/infinite-recursion-const-fn.rs:4:5
+   |
+LL |     b()
+   |     ^^^
+note: inside `b`
+  --> $DIR/infinite-recursion-const-fn.rs:7:5
+   |
+LL |     a()
+   |     ^^^
+note: inside `a`
+  --> $DIR/infinite-recursion-const-fn.rs:4:5
+   |
+LL |     b()
+   |     ^^^
+note: inside `b`
+  --> $DIR/infinite-recursion-const-fn.rs:7:5
+   |
+LL |     a()
+   |     ^^^
+note: inside `a`
+  --> $DIR/infinite-recursion-const-fn.rs:4:5
+   |
+LL |     b()
+   |     ^^^
+note: inside `b`
+  --> $DIR/infinite-recursion-const-fn.rs:7:5
+   |
+LL |     a()
+   |     ^^^
+note: inside `a`
+  --> $DIR/infinite-recursion-const-fn.rs:4:5
+   |
+LL |     b()
+   |     ^^^
+note: inside `ARR::{constant#0}`
+  --> $DIR/infinite-recursion-const-fn.rs:9:18
+   |
 LL | const ARR: [i32; a()] = [5; 6];
-   |                  --- inside `ARR::{constant#0}` at $DIR/infinite-recursion-const-fn.rs:9:18
+   |                  ^^^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/inline-const/expr-with-block-err.rs b/src/test/ui/inline-const/expr-with-block-err.rs
new file mode 100644 (file)
index 0000000..f754774
--- /dev/null
@@ -0,0 +1,6 @@
+#![feature(inline_const)]
+
+fn main() {
+    const { 2 } - const { 1 };
+    //~^ ERROR mismatched types
+}
diff --git a/src/test/ui/inline-const/expr-with-block-err.stderr b/src/test/ui/inline-const/expr-with-block-err.stderr
new file mode 100644 (file)
index 0000000..6f7408f
--- /dev/null
@@ -0,0 +1,9 @@
+error[E0308]: mismatched types
+  --> $DIR/expr-with-block-err.rs:4:13
+   |
+LL |     const { 2 } - const { 1 };
+   |             ^ expected `()`, found integer
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/inline-const/expr-with-block.rs b/src/test/ui/inline-const/expr-with-block.rs
new file mode 100644 (file)
index 0000000..3918724
--- /dev/null
@@ -0,0 +1,10 @@
+// check-pass
+#![feature(inline_const)]
+fn main() {
+    match true {
+        true => const {}
+        false => ()
+    }
+    const {}
+    ()
+}
index d328cafa00b9345f51bfbaa1b26de8bef76a4355..4600034952b395df64ffb824ea6a3b252be9beae 100644 (file)
@@ -4,7 +4,7 @@ error: invalid argument for `no_sanitize`
 LL | #[no_sanitize(brontosaurus)]
    |               ^^^^^^^^^^^^
    |
-   = note: expected one of: `address`, `cfi`, `hwaddress`, `memory`, `memtag`, `shadow-call-stack`, or `thread`
+   = note: expected one of: `address`, `cfi`, `hwaddress`, `kcfi`, `memory`, `memtag`, `shadow-call-stack`, or `thread`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-105330.rs b/src/test/ui/issues/issue-105330.rs
new file mode 100644 (file)
index 0000000..86e45f1
--- /dev/null
@@ -0,0 +1,21 @@
+pub trait TraitWAssocConst {
+    const A:   usize;
+}
+pub struct Demo {}
+
+impl TraitWAssocConst for impl Demo { //~ ERROR E0404
+    //~^ ERROR E0562
+    pubconst A: str = 32; //~ ERROR expected one of
+}
+
+fn foo<A: TraitWAssocConst<A=32>>() { //~ ERROR E0658
+    foo::<Demo>()(); //~ ERROR E0271
+    //~^ ERROR E0618
+    //~| ERROR E0277
+}
+
+fn main<A: TraitWAssocConst<A=32>>() { //~ ERROR E0131
+    //~^ ERROR E0658
+    foo::<Demo>(); //~ ERROR E0277
+    //~^ ERROR E0271
+}
diff --git a/src/test/ui/issues/issue-105330.stderr b/src/test/ui/issues/issue-105330.stderr
new file mode 100644 (file)
index 0000000..92f2ccb
--- /dev/null
@@ -0,0 +1,109 @@
+error: expected one of `!` or `::`, found `A`
+  --> $DIR/issue-105330.rs:8:14
+   |
+LL | impl TraitWAssocConst for impl Demo {
+   |                                     - while parsing this item list starting here
+LL |
+LL |     pubconst A: str = 32;
+   |              ^ expected one of `!` or `::`
+LL | }
+   | - the item list ends here
+
+error[E0404]: expected trait, found struct `Demo`
+  --> $DIR/issue-105330.rs:6:32
+   |
+LL | impl TraitWAssocConst for impl Demo {
+   |                                ^^^^ not a trait
+
+error[E0658]: associated const equality is incomplete
+  --> $DIR/issue-105330.rs:11:28
+   |
+LL | fn foo<A: TraitWAssocConst<A=32>>() {
+   |                            ^^^^
+   |
+   = note: see issue #92827 <https://github.com/rust-lang/rust/issues/92827> for more information
+   = help: add `#![feature(associated_const_equality)]` to the crate attributes to enable
+
+error[E0658]: associated const equality is incomplete
+  --> $DIR/issue-105330.rs:17:29
+   |
+LL | fn main<A: TraitWAssocConst<A=32>>() {
+   |                             ^^^^
+   |
+   = note: see issue #92827 <https://github.com/rust-lang/rust/issues/92827> for more information
+   = help: add `#![feature(associated_const_equality)]` to the crate attributes to enable
+
+error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in type
+  --> $DIR/issue-105330.rs:6:27
+   |
+LL | impl TraitWAssocConst for impl Demo {
+   |                           ^^^^^^^^^
+
+error[E0277]: the trait bound `Demo: TraitWAssocConst` is not satisfied
+  --> $DIR/issue-105330.rs:12:11
+   |
+LL |     foo::<Demo>()();
+   |           ^^^^ the trait `TraitWAssocConst` is not implemented for `Demo`
+   |
+note: required by a bound in `foo`
+  --> $DIR/issue-105330.rs:11:11
+   |
+LL | fn foo<A: TraitWAssocConst<A=32>>() {
+   |           ^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `foo`
+
+error[E0271]: type mismatch resolving `<Demo as TraitWAssocConst>::A == 32`
+  --> $DIR/issue-105330.rs:12:11
+   |
+LL |     foo::<Demo>()();
+   |           ^^^^ types differ
+   |
+note: required by a bound in `foo`
+  --> $DIR/issue-105330.rs:11:28
+   |
+LL | fn foo<A: TraitWAssocConst<A=32>>() {
+   |                            ^^^^ required by this bound in `foo`
+
+error[E0618]: expected function, found `()`
+  --> $DIR/issue-105330.rs:12:5
+   |
+LL | fn foo<A: TraitWAssocConst<A=32>>() {
+   | ----------------------------------- `foo::<Demo>` defined here returns `()`
+LL |     foo::<Demo>()();
+   |     ^^^^^^^^^^^^^--
+   |     |
+   |     call expression requires function
+
+error[E0277]: the trait bound `Demo: TraitWAssocConst` is not satisfied
+  --> $DIR/issue-105330.rs:19:11
+   |
+LL |     foo::<Demo>();
+   |           ^^^^ the trait `TraitWAssocConst` is not implemented for `Demo`
+   |
+note: required by a bound in `foo`
+  --> $DIR/issue-105330.rs:11:11
+   |
+LL | fn foo<A: TraitWAssocConst<A=32>>() {
+   |           ^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `foo`
+
+error[E0271]: type mismatch resolving `<Demo as TraitWAssocConst>::A == 32`
+  --> $DIR/issue-105330.rs:19:11
+   |
+LL |     foo::<Demo>();
+   |           ^^^^ types differ
+   |
+note: required by a bound in `foo`
+  --> $DIR/issue-105330.rs:11:28
+   |
+LL | fn foo<A: TraitWAssocConst<A=32>>() {
+   |                            ^^^^ required by this bound in `foo`
+
+error[E0131]: `main` function is not allowed to have generic parameters
+  --> $DIR/issue-105330.rs:17:8
+   |
+LL | fn main<A: TraitWAssocConst<A=32>>() {
+   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^ `main` cannot have generic parameters
+
+error: aborting due to 11 previous errors
+
+Some errors have detailed explanations: E0131, E0271, E0277, E0404, E0562, E0618, E0658.
+For more information about an error, try `rustc --explain E0131`.
index 91509ceace8cb3406806a91d1c75c54b504b47af..78df445972c94d34102044a095a0c10edc600cb4 100644 (file)
@@ -14,7 +14,7 @@ LL | impl<T> Foo for T where NoData<T>: Foo {
    |                                    ^^^
    |
    = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`issue_20413`)
-note: required for `NoData<NoData<NoData<NoData<NoData<NoData<...>>>>>>` to implement `Foo`
+note: required for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<...>>>>>>>>>>>>>` to implement `Foo`
   --> $DIR/issue-20413.rs:9:9
    |
 LL | impl<T> Foo for T where NoData<T>: Foo {
@@ -30,13 +30,13 @@ LL | impl<T> Bar for T where EvenLessData<T>: Baz {
    |                                          ^^^
    |
    = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`issue_20413`)
-note: required for `AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<...>>>>>>` to implement `Bar`
+note: required for `AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<...>>>>>>>` to implement `Bar`
   --> $DIR/issue-20413.rs:28:9
    |
 LL | impl<T> Bar for T where EvenLessData<T>: Baz {
    |         ^^^     ^
    = note: the full type name has been written to '$TEST_BUILD_DIR/issues/issue-20413/issue-20413.long-type-hash.txt'
-note: required for `EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<...>>>>>>` to implement `Baz`
+note: required for `EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<...>>>>>>>` to implement `Baz`
   --> $DIR/issue-20413.rs:35:9
    |
 LL | impl<T> Baz for T where AlmostNoData<T>: Bar {
@@ -52,13 +52,13 @@ LL | impl<T> Baz for T where AlmostNoData<T>: Bar {
    |                                          ^^^
    |
    = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`issue_20413`)
-note: required for `EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<...>>>>>>` to implement `Baz`
+note: required for `EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<...>>>>>>>` to implement `Baz`
   --> $DIR/issue-20413.rs:35:9
    |
 LL | impl<T> Baz for T where AlmostNoData<T>: Bar {
    |         ^^^     ^
    = note: the full type name has been written to '$TEST_BUILD_DIR/issues/issue-20413/issue-20413.long-type-hash.txt'
-note: required for `AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<...>>>>>>` to implement `Bar`
+note: required for `AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<...>>>>>>>` to implement `Bar`
   --> $DIR/issue-20413.rs:28:9
    |
 LL | impl<T> Bar for T where EvenLessData<T>: Baz {
index 5828e027b590312123168886eae1c2fc317ecf0a..1f50b06a0e4c553fc5b39160878ca3bd22c0d560 100644 (file)
@@ -5,7 +5,7 @@ LL |     type Next = <GetNext<T::Next> as Next>::Next;
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`issue_23122_2`)
-note: required for `GetNext<<<<<<... as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next>` to implement `Next`
+note: required for `GetNext<<<<<<<... as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next>` to implement `Next`
   --> $DIR/issue-23122-2.rs:10:15
    |
 LL | impl<T: Next> Next for GetNext<T> {
index ae8233d5c76e6aa2011bead773b94998c719182c..22c4055f54be31f93e2049780682bdf5a5bf255b 100644 (file)
@@ -11,7 +11,7 @@ note: required by a bound in `fold`
   --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
    |
 LL |         F: FnMut(B, Self::Item) -> B,
-   |            ^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `fold`
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Iterator::fold`
 
 error: aborting due to previous error
 
index 118f37f6971eff4856d69a966797b6d169059f67..1f51b6e29050cef2fa19e3c9659ae5442cd49bcd 100644 (file)
@@ -6,15 +6,10 @@ LL |     1.0f64 - 1
    |
    = help: the trait `Sub<{integer}>` is not implemented for `f64`
    = help: the following other types implement trait `Sub<Rhs>`:
-             <&'a f32 as Sub<f32>>
              <&'a f64 as Sub<f64>>
-             <&'a i128 as Sub<i128>>
-             <&'a i16 as Sub<i16>>
-             <&'a i32 as Sub<i32>>
-             <&'a i64 as Sub<i64>>
-             <&'a i8 as Sub<i8>>
-             <&'a isize as Sub<isize>>
-           and 48 others
+             <&f64 as Sub<&f64>>
+             <f64 as Sub<&f64>>
+             <f64 as Sub>
 help: consider using a floating-point literal by writing it with `.0`
    |
 LL |     1.0f64 - 1.0
index e3334eef3ad7f6c5e9bfd11af0f66495fc54a059..58d9b564427a723fd3583c954a26eae550fbbdd4 100644 (file)
@@ -18,7 +18,7 @@ note: required by a bound in `cloned`
   --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
    |
 LL |         Self: Sized + Iterator<Item = &'a T>,
-   |                                ^^^^^^^^^^^^ required by this bound in `cloned`
+   |                                ^^^^^^^^^^^^ required by this bound in `Iterator::cloned`
 
 error[E0599]: the method `collect` exists for struct `Cloned<TakeWhile<&mut std::vec::IntoIter<u8>, [closure@$DIR/issue-31173.rs:8:21: 8:25]>>`, but its trait bounds were not satisfied
   --> $DIR/issue-31173.rs:13:10
index 691b8f88f4ed54c87d6e65b5f9c1614d81e73a34..c28986a29854b0dfa4a241115a2391e980bfe4ba 100644 (file)
@@ -12,7 +12,7 @@ note: required by a bound in `cloned`
   --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
    |
 LL |         Self: Sized + Iterator<Item = &'a T>,
-   |                                ^^^^^^^^^^^^ required by this bound in `cloned`
+   |                                ^^^^^^^^^^^^ required by this bound in `Iterator::cloned`
 
 error[E0271]: expected `std::collections::hash_map::Iter<'_, _, _>` to be an iterator that yields `&_`, but it yields `(&_, &_)`
   --> $DIR/issue-33941.rs:6:14
index 72082f0cd17287650dbb42d4a341c419ab782df0..3188cd80cca8325037f4bf9f6a139b993b642021 100644 (file)
@@ -26,7 +26,7 @@ note: required by a bound in `collect`
   --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
    |
 LL |     fn collect<B: FromIterator<Self::Item>>(self) -> B
-   |                   ^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `collect`
+   |                   ^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Iterator::collect`
 
 error: aborting due to 2 previous errors
 
index d075794d9946fe40da855c4234695fbb230c95fd..aa6f74cb5d45ae0ffd98fd5d231cd79d67198f91 100644 (file)
@@ -1,5 +1,9 @@
+// revisions: imported unimported
+//[imported] check-pass
+
 mod private {
     pub trait Future {
+        //[unimported]~^^ HELP perhaps add a `use` for it
         fn wait(&self) where Self: Sized;
     }
 
@@ -8,13 +12,13 @@ fn wait(&self) { }
     }
 }
 
-//use private::Future;
+#[cfg(imported)]
+use private::Future;
 
 fn bar(arg: Box<dyn private::Future>) {
+    // Importing the trait means that we don't autoderef `Box<dyn Future>`
     arg.wait();
-    //~^ ERROR the `wait` method cannot be invoked on a trait object
+    //[unimported]~^ ERROR the `wait` method cannot be invoked on a trait object
 }
 
-fn main() {
-
-}
+fn main() {}
diff --git a/src/test/ui/issues/issue-35976.stderr b/src/test/ui/issues/issue-35976.stderr
deleted file mode 100644 (file)
index fe16f97..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-error: the `wait` method cannot be invoked on a trait object
-  --> $DIR/issue-35976.rs:14:9
-   |
-LL |         fn wait(&self) where Self: Sized;
-   |                                    ----- this has a `Sized` requirement
-...
-LL |     arg.wait();
-   |         ^^^^
-
-error: aborting due to previous error
-
diff --git a/src/test/ui/issues/issue-35976.unimported.stderr b/src/test/ui/issues/issue-35976.unimported.stderr
new file mode 100644 (file)
index 0000000..5d61bb8
--- /dev/null
@@ -0,0 +1,16 @@
+error: the `wait` method cannot be invoked on a trait object
+  --> $DIR/issue-35976.rs:20:9
+   |
+LL |         fn wait(&self) where Self: Sized;
+   |                                    ----- this has a `Sized` requirement
+...
+LL |     arg.wait();
+   |         ^^^^
+   |
+help: another candidate was found in the following trait, perhaps add a `use` for it:
+   |
+LL | use private::Future;
+   |
+
+error: aborting due to previous error
+
index 2bd24f08c1e51d0efb6cb4c272b6dc12d1e19c50..c7e9af70e64a791e6fcaa489dfbab558c203846f 100644 (file)
@@ -2,7 +2,9 @@ error[E0308]: mismatched types
   --> $DIR/issue-47486.rs:2:10
    |
 LL |     () < std::mem::size_of::<_>();
-   |          ^^^^^^^^^^^^^^^^^^^^^^^^ expected `()`, found `usize`
+   |     --   ^^^^^^^^^^^^^^^^^^^^^^^^ expected `()`, found `usize`
+   |     |
+   |     expected because this is `()`
 
 error[E0282]: type annotations needed
   --> $DIR/issue-47486.rs:3:11
index 2de15037650825da8c9abd1ba74b69f1ae523fc7..ce38c3320bb354ac11ec64c6058de2cc14254788 100644 (file)
@@ -12,7 +12,7 @@ note: required by a bound in `collect`
   --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
    |
 LL |     fn collect<B: FromIterator<Self::Item>>(self) -> B
-   |                   ^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `collect`
+   |                   ^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Iterator::collect`
 
 error[E0277]: a value of type `Vec<f64>` cannot be built from an iterator over elements of type `&f64`
   --> $DIR/issue-66923-show-error-for-correct-call.rs:12:14
@@ -28,7 +28,7 @@ note: required by a bound in `collect`
   --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
    |
 LL |     fn collect<B: FromIterator<Self::Item>>(self) -> B
-   |                   ^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `collect`
+   |                   ^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Iterator::collect`
 
 error: aborting due to 2 previous errors
 
index a23a36a88abb336dd24a54ec7ce3f41c9654ee90..544b1da178a3d96bfed1d5f654444b110d7d07d2 100644 (file)
@@ -11,7 +11,7 @@ note: required by a bound in `collect`
   --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
    |
 LL |     fn collect<B: FromIterator<Self::Item>>(self) -> B
-   |                   ^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `collect`
+   |                   ^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Iterator::collect`
 
 error: aborting due to previous error
 
index bc152467ce3a5c5d94d1c06ca790ec3793a38492..65ef124a46302ec2197356494f86495325f8d16e 100644 (file)
@@ -19,7 +19,7 @@ note: required by a bound in `collect`
   --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
    |
 LL |     fn collect<B: FromIterator<Self::Item>>(self) -> B
-   |                ^ required by this bound in `collect`
+   |                ^ required by this bound in `Iterator::collect`
 
 error[E0277]: a slice of type `[i32]` cannot be built since `[i32]` has no definite size
   --> $DIR/collect-into-slice.rs:6:30
@@ -34,7 +34,7 @@ note: required by a bound in `collect`
   --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
    |
 LL |     fn collect<B: FromIterator<Self::Item>>(self) -> B
-   |                   ^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `collect`
+   |                   ^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Iterator::collect`
 
 error: aborting due to 3 previous errors
 
index 025a5008d0f11f0d1aacfb8d041554be1dd149fc..9af89159a8cfcec0f98cf91bcbbff4f358b7e34d 100644 (file)
@@ -4,16 +4,7 @@ error[E0277]: the trait bound `&'static mut isize: Copy` is not satisfied
 LL |     assert_copy::<&'static mut isize>();
    |                   ^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `&'static mut isize`
    |
-   = help: the following other types implement trait `Copy`:
-             f32
-             f64
-             i128
-             i16
-             i32
-             i64
-             i8
-             isize
-           and 6 others
+   = help: the trait `Copy` is implemented for `isize`
 note: required by a bound in `assert_copy`
   --> $DIR/kindck-copy.rs:5:18
    |
@@ -26,16 +17,7 @@ error[E0277]: the trait bound `&'a mut isize: Copy` is not satisfied
 LL |     assert_copy::<&'a mut isize>();
    |                   ^^^^^^^^^^^^^ the trait `Copy` is not implemented for `&'a mut isize`
    |
-   = help: the following other types implement trait `Copy`:
-             f32
-             f64
-             i128
-             i16
-             i32
-             i64
-             i8
-             isize
-           and 6 others
+   = help: the trait `Copy` is implemented for `isize`
 note: required by a bound in `assert_copy`
   --> $DIR/kindck-copy.rs:5:18
    |
index 33f82448dd2acd87fd701c178ba088ceede166d0..5a46027dd52ba9c8fd50cb06bc0805267f01987b 100644 (file)
@@ -11,7 +11,7 @@ note: required by a bound in `collect`
   --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
    |
 LL |     fn collect<B: FromIterator<Self::Item>>(self) -> B
-   |                   ^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `collect`
+   |                   ^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Iterator::collect`
 
 error: aborting due to previous error
 
index 57978edf2bf0505fc9397326d8f8a3149abd874b..a4b4968b7d24c98011d4184c5ad7af63024ab124 100644 (file)
@@ -11,7 +11,7 @@ note: required by a bound in `collect`
   --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
    |
 LL |     fn collect<B: FromIterator<Self::Item>>(self) -> B
-   |                   ^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `collect`
+   |                   ^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Iterator::collect`
 
 error[E0277]: a value of type `impl Debug` cannot be built from an iterator over elements of type `_`
   --> $DIR/recursion4.rs:19:9
@@ -26,7 +26,7 @@ note: required by a bound in `collect`
   --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
    |
 LL |     fn collect<B: FromIterator<Self::Item>>(self) -> B
-   |                   ^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `collect`
+   |                   ^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Iterator::collect`
 
 error: aborting due to 2 previous errors
 
index addcd798f4ffb8f54cfa21d2345e7969138caf6b..bf78a079cdfa9fd766e270a488ae65ac63c299a0 100644 (file)
@@ -12,7 +12,7 @@ error[E0308]: mismatched types
 LL |         let Bar(z) = x;
    |             ^^^^^^   - this expression has type `&mut irrefutable::Foo`
    |             |
-   |             expected struct `irrefutable::Foo`, found struct `irrefutable::Bar`
+   |             expected struct `Foo`, found struct `Bar`
 
 error: aborting due to 2 previous errors
 
index afef0cb603485712c74f5c556b68508b2ecd3da9..ce41942467cea1a9fb34bcfe201485e2cbd3bd34 100644 (file)
@@ -42,12 +42,11 @@ LL |     if x == y {}
              <&'a str as PartialEq<OsString>>
              <&'a str as PartialEq<String>>
              <&'b str as PartialEq<Cow<'a, str>>>
-             <String as PartialEq<&'a str>>
-             <String as PartialEq<Cow<'a, str>>>
-             <String as PartialEq<str>>
-             <String as PartialEq>
              <str as PartialEq<Cow<'a, str>>>
-           and 4 others
+             <str as PartialEq<OsStr>>
+             <str as PartialEq<OsString>>
+             <str as PartialEq<String>>
+             <str as PartialEq>
 
 error[E0308]: mismatched types
   --> $DIR/lex-bad-char-literals-6.rs:15:20
@@ -68,12 +67,11 @@ LL |     if x == z {}
              <&'a str as PartialEq<OsString>>
              <&'a str as PartialEq<String>>
              <&'b str as PartialEq<Cow<'a, str>>>
-             <String as PartialEq<&'a str>>
-             <String as PartialEq<Cow<'a, str>>>
-             <String as PartialEq<str>>
-             <String as PartialEq>
              <str as PartialEq<Cow<'a, str>>>
-           and 4 others
+             <str as PartialEq<OsStr>>
+             <str as PartialEq<OsString>>
+             <str as PartialEq<String>>
+             <str as PartialEq>
 
 error: aborting due to 6 previous errors
 
index e35f9f14c7ecc0215ffa4ad4e7092a1ed7536093..f17f8141b909a442c7897f818c30e2090c90df23 100644 (file)
@@ -2,12 +2,18 @@ error[E0080]: values of the type `[u8; SIZE]` are too big for the current archit
   --> $SRC_DIR/core/src/mem/mod.rs:LL:COL
    |
 LL |     intrinsics::size_of::<T>()
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^ inside `std::mem::size_of::<[u8; SIZE]>` at $SRC_DIR/core/src/mem/mod.rs:LL:COL
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-  ::: $DIR/issue-55878.rs:7:26
+note: inside `std::mem::size_of::<[u8; SIZE]>`
+  --> $SRC_DIR/core/src/mem/mod.rs:LL:COL
+   |
+LL |     intrinsics::size_of::<T>()
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
+note: inside `main`
+  --> $DIR/issue-55878.rs:7:26
    |
 LL |     println!("Size: {}", std::mem::size_of::<[u8; u64::MAX as usize]>());
-   |                          ---------------------------------------------- inside `main` at $DIR/issue-55878.rs:7:26
+   |                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 note: erroneous constant used
   --> $DIR/issue-55878.rs:7:26
diff --git a/src/test/ui/linkage-attr/auxiliary/def_external.rs b/src/test/ui/linkage-attr/auxiliary/def_external.rs
new file mode 100644 (file)
index 0000000..2300930
--- /dev/null
@@ -0,0 +1,5 @@
+#![feature(linkage)]
+#![crate_type = "lib"]
+
+#[linkage="external"]
+pub static EXTERN: u32 = 0;
diff --git a/src/test/ui/linkage-attr/auxiliary/def_illtyped_external.rs b/src/test/ui/linkage-attr/auxiliary/def_illtyped_external.rs
deleted file mode 100644 (file)
index 2300930..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-#![feature(linkage)]
-#![crate_type = "lib"]
-
-#[linkage="external"]
-pub static EXTERN: u32 = 0;
diff --git a/src/test/ui/linkage-attr/linkage-import.rs b/src/test/ui/linkage-attr/linkage-import.rs
new file mode 100644 (file)
index 0000000..f754ddc
--- /dev/null
@@ -0,0 +1,8 @@
+// build-pass
+// aux-build:def_external.rs
+
+extern crate def_external as dep;
+
+fn main() {
+    println!("{:p}", &dep::EXTERN);
+}
diff --git a/src/test/ui/linkage-attr/linkage-requires-raw-ptr.rs b/src/test/ui/linkage-attr/linkage-requires-raw-ptr.rs
deleted file mode 100644 (file)
index 93afc53..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-// rust-lang/rust#59548: We used to ICE when trying to use a static
-// with a type that violated its own `#[linkage]`.
-
-// build-fail
-// aux-build:def_illtyped_external.rs
-
-extern crate def_illtyped_external as dep;
-
-fn main() {
-    println!("{:p}", &dep::EXTERN);
-}
diff --git a/src/test/ui/linkage-attr/linkage-requires-raw-ptr.stderr b/src/test/ui/linkage-attr/linkage-requires-raw-ptr.stderr
deleted file mode 100644 (file)
index 5abbe74..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-error: must have type `*const T` or `*mut T` due to `#[linkage]` attribute
-  --> $DIR/auxiliary/def_illtyped_external.rs:5:1
-   |
-LL | pub static EXTERN: u32 = 0;
-   | ^^^^^^^^^^^^^^^^^^^^^^
-
-error: aborting due to previous error
-
index a7be1985286a1373dcefaf3994e0d991b62403cf..aa42874f7ba8a64767d80708e2282fb1e349d88c 100644 (file)
@@ -1,16 +1,11 @@
-// FIXME https://github.com/rust-lang/rust/issues/59774
-
-// build-fail
-// normalize-stderr-test "thread.*panicked.*Metadata module not compiled.*\n" -> ""
-// normalize-stderr-test "note:.*RUST_BACKTRACE=1.*\n" -> ""
-// ignore-sgx no weak linkages permitted
+// check-fail
 
 #![feature(linkage)]
 
 extern "C" {
     #[linkage = "extern_weak"]
     static foo: i32;
-//~^ ERROR: must have type `*const T` or `*mut T` due to `#[linkage]` attribute
+//~^ ERROR: invalid type for variable with `#[linkage]` attribute
 }
 
 fn main() {
index a6ac0aad077874d6b70ce71adced4dab7bad5e65..7265f711fd01643ca2020957052fadab196312d4 100644 (file)
@@ -1,8 +1,9 @@
-error: must have type `*const T` or `*mut T` due to `#[linkage]` attribute
-  --> $DIR/linkage2.rs:12:5
+error[E0791]: invalid type for variable with `#[linkage]` attribute
+  --> $DIR/linkage2.rs:7:5
    |
 LL |     static foo: i32;
    |     ^^^^^^^^^^^^^^^
 
 error: aborting due to previous error
 
+For more information about this error, try `rustc --explain E0791`.
diff --git a/src/test/ui/lint/issue-104897.rs b/src/test/ui/lint/issue-104897.rs
new file mode 100644 (file)
index 0000000..5fbc658
--- /dev/null
@@ -0,0 +1,6 @@
+// error-pattern: this file contains an unclosed delimiter
+// error-pattern: this file contains an unclosed delimiter
+// error-pattern: this file contains an unclosed delimiter
+// error-pattern: format argument must be a string literal
+
+fn f(){(print!(á
diff --git a/src/test/ui/lint/issue-104897.stderr b/src/test/ui/lint/issue-104897.stderr
new file mode 100644 (file)
index 0000000..817a93c
--- /dev/null
@@ -0,0 +1,43 @@
+error: this file contains an unclosed delimiter
+  --> $DIR/issue-104897.rs:6:18
+   |
+LL | fn f(){(print!(á
+   |       --      -  ^
+   |       ||      |
+   |       ||      unclosed delimiter
+   |       |unclosed delimiter
+   |       unclosed delimiter
+
+error: this file contains an unclosed delimiter
+  --> $DIR/issue-104897.rs:6:18
+   |
+LL | fn f(){(print!(á
+   |       --      -  ^
+   |       ||      |
+   |       ||      unclosed delimiter
+   |       |unclosed delimiter
+   |       unclosed delimiter
+
+error: this file contains an unclosed delimiter
+  --> $DIR/issue-104897.rs:6:18
+   |
+LL | fn f(){(print!(á
+   |       --      -  ^
+   |       ||      |
+   |       ||      unclosed delimiter
+   |       |unclosed delimiter
+   |       unclosed delimiter
+
+error: format argument must be a string literal
+  --> $DIR/issue-104897.rs:6:16
+   |
+LL | fn f(){(print!(á
+   |                ^
+   |
+help: you might be missing a string literal to format with
+   |
+LL | fn f(){(print!("{}", Ã¡
+   |                +++++
+
+error: aborting due to 4 previous errors
+
diff --git a/src/test/ui/lint/issue-97094.interleaved.stderr b/src/test/ui/lint/issue-97094.interleaved.stderr
deleted file mode 100644 (file)
index a258165..0000000
+++ /dev/null
@@ -1,53 +0,0 @@
-error: unknown lint: `nonex_lint_top_level`
-  --> $DIR/issue-97094.rs:14:26
-   |
-LL | #![cfg_attr(all(), allow(nonex_lint_top_level))]
-   |                          ^^^^^^^^^^^^^^^^^^^^
-   |
-note: the lint level is defined here
-  --> $DIR/issue-97094.rs:10:9
-   |
-LL | #![deny(warnings)]
-   |         ^^^^^^^^
-   = note: `#[deny(unknown_lints)]` implied by `#[deny(warnings)]`
-
-error: lint `bare_trait_object` has been renamed to `bare_trait_objects`
-  --> $DIR/issue-97094.rs:16:26
-   |
-LL | #![cfg_attr(all(), allow(bare_trait_object))]
-   |                          ^^^^^^^^^^^^^^^^^ help: use the new name: `bare_trait_objects`
-   |
-   = note: `#[deny(renamed_and_removed_lints)]` implied by `#[deny(warnings)]`
-
-error: unknown lint: `nonex_lint_mod`
-  --> $DIR/issue-97094.rs:19:25
-   |
-LL | #[cfg_attr(all(), allow(nonex_lint_mod))]
-   |                         ^^^^^^^^^^^^^^
-
-error: unknown lint: `nonex_lint_mod_inner`
-  --> $DIR/issue-97094.rs:22:30
-   |
-LL |     #![cfg_attr(all(), allow(nonex_lint_mod_inner))]
-   |                              ^^^^^^^^^^^^^^^^^^^^
-
-error: unknown lint: `nonex_lint_fn`
-  --> $DIR/issue-97094.rs:26:25
-   |
-LL | #[cfg_attr(all(), allow(nonex_lint_fn))]
-   |                         ^^^^^^^^^^^^^
-
-error: unknown lint: `nonex_lint_in_macro`
-  --> $DIR/issue-97094.rs:37:29
-   |
-LL |     #[cfg_attr(all(), allow(nonex_lint_in_macro))]
-   |                             ^^^^^^^^^^^^^^^^^^^
-
-error: unknown lint: `nonex_lint_fn`
-  --> $DIR/issue-97094.rs:56:13
-   |
-LL |     #[allow(nonex_lint_fn)]
-   |             ^^^^^^^^^^^^^
-
-error: aborting due to 7 previous errors
-
diff --git a/src/test/ui/lint/issue-97094.nointerleaved.stderr b/src/test/ui/lint/issue-97094.nointerleaved.stderr
deleted file mode 100644 (file)
index a258165..0000000
+++ /dev/null
@@ -1,53 +0,0 @@
-error: unknown lint: `nonex_lint_top_level`
-  --> $DIR/issue-97094.rs:14:26
-   |
-LL | #![cfg_attr(all(), allow(nonex_lint_top_level))]
-   |                          ^^^^^^^^^^^^^^^^^^^^
-   |
-note: the lint level is defined here
-  --> $DIR/issue-97094.rs:10:9
-   |
-LL | #![deny(warnings)]
-   |         ^^^^^^^^
-   = note: `#[deny(unknown_lints)]` implied by `#[deny(warnings)]`
-
-error: lint `bare_trait_object` has been renamed to `bare_trait_objects`
-  --> $DIR/issue-97094.rs:16:26
-   |
-LL | #![cfg_attr(all(), allow(bare_trait_object))]
-   |                          ^^^^^^^^^^^^^^^^^ help: use the new name: `bare_trait_objects`
-   |
-   = note: `#[deny(renamed_and_removed_lints)]` implied by `#[deny(warnings)]`
-
-error: unknown lint: `nonex_lint_mod`
-  --> $DIR/issue-97094.rs:19:25
-   |
-LL | #[cfg_attr(all(), allow(nonex_lint_mod))]
-   |                         ^^^^^^^^^^^^^^
-
-error: unknown lint: `nonex_lint_mod_inner`
-  --> $DIR/issue-97094.rs:22:30
-   |
-LL |     #![cfg_attr(all(), allow(nonex_lint_mod_inner))]
-   |                              ^^^^^^^^^^^^^^^^^^^^
-
-error: unknown lint: `nonex_lint_fn`
-  --> $DIR/issue-97094.rs:26:25
-   |
-LL | #[cfg_attr(all(), allow(nonex_lint_fn))]
-   |                         ^^^^^^^^^^^^^
-
-error: unknown lint: `nonex_lint_in_macro`
-  --> $DIR/issue-97094.rs:37:29
-   |
-LL |     #[cfg_attr(all(), allow(nonex_lint_in_macro))]
-   |                             ^^^^^^^^^^^^^^^^^^^
-
-error: unknown lint: `nonex_lint_fn`
-  --> $DIR/issue-97094.rs:56:13
-   |
-LL |     #[allow(nonex_lint_fn)]
-   |             ^^^^^^^^^^^^^
-
-error: aborting due to 7 previous errors
-
index aeaead1bd11bd5577b126633c2f0e601112e71da..22525ca11ae04cefa3abbb465c9beb527e49cc30 100644 (file)
@@ -1,12 +1,3 @@
-// revisions: interleaved nointerleaved
-// [nointerleaved]compile-flags: -Z no-interleave-lints
-
-// This test has two revisions because the logic change
-// needed to make this test pass had to be adjusted
-// for no-interleave-lints. Should the debug option
-// be removed one day, please don't remove this
-// test entirely, just remove the revision from it.
-
 #![deny(warnings)]
 
 // Ensure that unknown lints inside cfg-attr's are linted for
diff --git a/src/test/ui/lint/issue-97094.stderr b/src/test/ui/lint/issue-97094.stderr
new file mode 100644 (file)
index 0000000..1a0a3ea
--- /dev/null
@@ -0,0 +1,53 @@
+error: unknown lint: `nonex_lint_top_level`
+  --> $DIR/issue-97094.rs:5:26
+   |
+LL | #![cfg_attr(all(), allow(nonex_lint_top_level))]
+   |                          ^^^^^^^^^^^^^^^^^^^^
+   |
+note: the lint level is defined here
+  --> $DIR/issue-97094.rs:1:9
+   |
+LL | #![deny(warnings)]
+   |         ^^^^^^^^
+   = note: `#[deny(unknown_lints)]` implied by `#[deny(warnings)]`
+
+error: lint `bare_trait_object` has been renamed to `bare_trait_objects`
+  --> $DIR/issue-97094.rs:7:26
+   |
+LL | #![cfg_attr(all(), allow(bare_trait_object))]
+   |                          ^^^^^^^^^^^^^^^^^ help: use the new name: `bare_trait_objects`
+   |
+   = note: `#[deny(renamed_and_removed_lints)]` implied by `#[deny(warnings)]`
+
+error: unknown lint: `nonex_lint_mod`
+  --> $DIR/issue-97094.rs:10:25
+   |
+LL | #[cfg_attr(all(), allow(nonex_lint_mod))]
+   |                         ^^^^^^^^^^^^^^
+
+error: unknown lint: `nonex_lint_mod_inner`
+  --> $DIR/issue-97094.rs:13:30
+   |
+LL |     #![cfg_attr(all(), allow(nonex_lint_mod_inner))]
+   |                              ^^^^^^^^^^^^^^^^^^^^
+
+error: unknown lint: `nonex_lint_fn`
+  --> $DIR/issue-97094.rs:17:25
+   |
+LL | #[cfg_attr(all(), allow(nonex_lint_fn))]
+   |                         ^^^^^^^^^^^^^
+
+error: unknown lint: `nonex_lint_in_macro`
+  --> $DIR/issue-97094.rs:28:29
+   |
+LL |     #[cfg_attr(all(), allow(nonex_lint_in_macro))]
+   |                             ^^^^^^^^^^^^^^^^^^^
+
+error: unknown lint: `nonex_lint_fn`
+  --> $DIR/issue-97094.rs:47:13
+   |
+LL |     #[allow(nonex_lint_fn)]
+   |             ^^^^^^^^^^^^^
+
+error: aborting due to 7 previous errors
+
diff --git a/src/test/ui/lint/lint-missing-copy-implementations-allow.rs b/src/test/ui/lint/lint-missing-copy-implementations-allow.rs
new file mode 100644 (file)
index 0000000..051a905
--- /dev/null
@@ -0,0 +1,35 @@
+// check-pass
+#![deny(missing_copy_implementations)]
+
+// Don't recommend implementing Copy on something stateful like an iterator.
+pub struct MyIterator {
+    num: u8,
+}
+
+impl Iterator for MyIterator {
+    type Item = u8;
+
+    fn next(&mut self) -> Option<Self::Item> {
+        todo!()
+    }
+}
+
+pub struct Handle {
+    inner: *mut (),
+}
+
+pub struct Handle2 {
+    inner: *const (),
+}
+
+pub enum MaybeHandle {
+    Ptr(*mut ()),
+}
+
+pub union UnionHandle {
+    ptr: *mut (),
+}
+
+pub struct Array([u8; 2048]);
+
+fn main() {}
index 0b3fe9371f7758a63a2fbd098d3007583031f0e0..71ebaea8ed2c185cc296dab497d1e0eb638e96e5 100644 (file)
@@ -1,6 +1,6 @@
 // run-rustfix
 
-#![feature(box_patterns, stmt_expr_attributes)]
+#![feature(box_patterns, stmt_expr_attributes, yeet_expr)]
 
 #![allow(
     dead_code,
@@ -25,6 +25,13 @@ fn _no_lint_attr() {
     let _x = #[allow(dead_code)] (1 + 2);
 }
 
+fn _no_lint_yeet() -> Result<(), ()> {
+    #[allow(unreachable_code)]
+    if (do yeet) {}
+
+    Ok(())
+}
+
 // Don't lint in these cases (#64106).
 fn or_patterns_no_lint() {
     match Box::new(0) {
index 1e78ec5f7d95de02d7483ffe4e20097066a1ed12..28b662dd0242c8715c7ba5e8e22d34426f8537a4 100644 (file)
@@ -1,6 +1,6 @@
 // run-rustfix
 
-#![feature(box_patterns, stmt_expr_attributes)]
+#![feature(box_patterns, stmt_expr_attributes, yeet_expr)]
 
 #![allow(
     dead_code,
@@ -25,6 +25,13 @@ fn _no_lint_attr() {
     let _x = #[allow(dead_code)] (1 + 2);
 }
 
+fn _no_lint_yeet() -> Result<(), ()> {
+    #[allow(unreachable_code)]
+    if (do yeet) {}
+
+    Ok(())
+}
+
 // Don't lint in these cases (#64106).
 fn or_patterns_no_lint() {
     match Box::new(0) {
index c73884663c8f5adf06e6b8d3036a5c58aafe8cbf..a5e69e6d9385cc9db896856f81550bd1ce9cbf9c 100644 (file)
@@ -76,7 +76,7 @@ LL +     let _ = |a: u8| 0;
    |
 
 error: unnecessary parentheses around pattern
-  --> $DIR/issue-54538-unused-parens-lint.rs:49:12
+  --> $DIR/issue-54538-unused-parens-lint.rs:56:12
    |
 LL |     if let (0 | 1) = 0 {}
    |            ^     ^
@@ -88,7 +88,7 @@ LL +     if let 0 | 1 = 0 {}
    |
 
 error: unnecessary parentheses around pattern
-  --> $DIR/issue-54538-unused-parens-lint.rs:50:13
+  --> $DIR/issue-54538-unused-parens-lint.rs:57:13
    |
 LL |     if let ((0 | 1),) = (0,) {}
    |             ^     ^
@@ -100,7 +100,7 @@ LL +     if let (0 | 1,) = (0,) {}
    |
 
 error: unnecessary parentheses around pattern
-  --> $DIR/issue-54538-unused-parens-lint.rs:51:13
+  --> $DIR/issue-54538-unused-parens-lint.rs:58:13
    |
 LL |     if let [(0 | 1)] = [0] {}
    |             ^     ^
@@ -112,7 +112,7 @@ LL +     if let [0 | 1] = [0] {}
    |
 
 error: unnecessary parentheses around pattern
-  --> $DIR/issue-54538-unused-parens-lint.rs:52:16
+  --> $DIR/issue-54538-unused-parens-lint.rs:59:16
    |
 LL |     if let 0 | (1 | 2) = 0 {}
    |                ^     ^
@@ -124,7 +124,7 @@ LL +     if let 0 | 1 | 2 = 0 {}
    |
 
 error: unnecessary parentheses around pattern
-  --> $DIR/issue-54538-unused-parens-lint.rs:54:15
+  --> $DIR/issue-54538-unused-parens-lint.rs:61:15
    |
 LL |     if let TS((0 | 1)) = TS(0) {}
    |               ^     ^
@@ -136,7 +136,7 @@ LL +     if let TS(0 | 1) = TS(0) {}
    |
 
 error: unnecessary parentheses around pattern
-  --> $DIR/issue-54538-unused-parens-lint.rs:56:20
+  --> $DIR/issue-54538-unused-parens-lint.rs:63:20
    |
 LL |     if let NS { f: (0 | 1) } = (NS { f: 0 }) {}
    |                    ^     ^
@@ -148,7 +148,7 @@ LL +     if let NS { f: 0 | 1 } = (NS { f: 0 }) {}
    |
 
 error: unnecessary parentheses around pattern
-  --> $DIR/issue-54538-unused-parens-lint.rs:66:9
+  --> $DIR/issue-54538-unused-parens-lint.rs:73:9
    |
 LL |         (_) => {}
    |         ^ ^
@@ -160,7 +160,7 @@ LL +         _ => {}
    |
 
 error: unnecessary parentheses around pattern
-  --> $DIR/issue-54538-unused-parens-lint.rs:67:9
+  --> $DIR/issue-54538-unused-parens-lint.rs:74:9
    |
 LL |         (y) => {}
    |         ^ ^
@@ -172,7 +172,7 @@ LL +         y => {}
    |
 
 error: unnecessary parentheses around pattern
-  --> $DIR/issue-54538-unused-parens-lint.rs:68:9
+  --> $DIR/issue-54538-unused-parens-lint.rs:75:9
    |
 LL |         (ref r) => {}
    |         ^     ^
@@ -184,7 +184,7 @@ LL +         ref r => {}
    |
 
 error: unnecessary parentheses around pattern
-  --> $DIR/issue-54538-unused-parens-lint.rs:69:9
+  --> $DIR/issue-54538-unused-parens-lint.rs:76:9
    |
 LL |         (e @ 1...2) => {}
    |         ^         ^
@@ -196,7 +196,7 @@ LL +         e @ 1...2 => {}
    |
 
 error: unnecessary parentheses around pattern
-  --> $DIR/issue-54538-unused-parens-lint.rs:75:9
+  --> $DIR/issue-54538-unused-parens-lint.rs:82:9
    |
 LL |         (e @ &(1...2)) => {}
    |         ^            ^
@@ -208,7 +208,7 @@ LL +         e @ &(1...2) => {}
    |
 
 error: unnecessary parentheses around pattern
-  --> $DIR/issue-54538-unused-parens-lint.rs:76:10
+  --> $DIR/issue-54538-unused-parens-lint.rs:83:10
    |
 LL |         &(_) => {}
    |          ^ ^
@@ -220,7 +220,7 @@ LL +         &_ => {}
    |
 
 error: unnecessary parentheses around pattern
-  --> $DIR/issue-54538-unused-parens-lint.rs:87:9
+  --> $DIR/issue-54538-unused-parens-lint.rs:94:9
    |
 LL |         (_) => {}
    |         ^ ^
@@ -232,7 +232,7 @@ LL +         _ => {}
    |
 
 error: unnecessary parentheses around pattern
-  --> $DIR/issue-54538-unused-parens-lint.rs:88:9
+  --> $DIR/issue-54538-unused-parens-lint.rs:95:9
    |
 LL |         (y) => {}
    |         ^ ^
@@ -244,7 +244,7 @@ LL +         y => {}
    |
 
 error: unnecessary parentheses around pattern
-  --> $DIR/issue-54538-unused-parens-lint.rs:89:9
+  --> $DIR/issue-54538-unused-parens-lint.rs:96:9
    |
 LL |         (ref r) => {}
    |         ^     ^
@@ -256,7 +256,7 @@ LL +         ref r => {}
    |
 
 error: unnecessary parentheses around pattern
-  --> $DIR/issue-54538-unused-parens-lint.rs:90:9
+  --> $DIR/issue-54538-unused-parens-lint.rs:97:9
    |
 LL |         (e @ 1..=2) => {}
    |         ^         ^
@@ -268,7 +268,7 @@ LL +         e @ 1..=2 => {}
    |
 
 error: unnecessary parentheses around pattern
-  --> $DIR/issue-54538-unused-parens-lint.rs:96:9
+  --> $DIR/issue-54538-unused-parens-lint.rs:103:9
    |
 LL |         (e @ &(1..=2)) => {}
    |         ^            ^
@@ -280,7 +280,7 @@ LL +         e @ &(1..=2) => {}
    |
 
 error: unnecessary parentheses around pattern
-  --> $DIR/issue-54538-unused-parens-lint.rs:97:10
+  --> $DIR/issue-54538-unused-parens-lint.rs:104:10
    |
 LL |         &(_) => {}
    |          ^ ^
index be02fcd3f00c7e5b81eb2835adaa91fe0258a77e..ce3d15ac183fecd1dabc232dcfed9174d2fa1577 100644 (file)
@@ -51,22 +51,13 @@ fn inside_if() -> u8 {
 
 mod typeascription {
     fn outside() -> u8 {
-        ({ 0 }): u8
-    }
-    fn inside() -> u8 {
-        ({ 0 }: u8)
+        type_ascribe!(({ 0 }), u8)
     }
     fn outside_match() -> u8 {
-        (match 0 { x => x }): u8
-    }
-    fn inside_match() -> u8 {
-        (match 0 { x => x }: u8)
+        type_ascribe!((match 0 { x => x }), u8)
     }
     fn outside_if() -> u8 {
-        (if false { 0 } else { 0 }): u8
-    }
-    fn inside_if() -> u8 {
-        (if false { 0 } else { 0 }: u8)
+        type_ascribe!((if false { 0 } else { 0 }), u8)
     }
 }
 
diff --git a/src/test/ui/macros/issue-103529.rs b/src/test/ui/macros/issue-103529.rs
new file mode 100644 (file)
index 0000000..fa05bae
--- /dev/null
@@ -0,0 +1,13 @@
+macro_rules! m {
+    ($s:stmt) => {}
+}
+
+m! { mut x }
+//~^ ERROR expected expression, found keyword `mut`
+//~| ERROR expected a statement
+m! { auto x }
+//~^ ERROR invalid variable declaration
+m! { var x }
+//~^ ERROR invalid variable declaration
+
+fn main() {}
diff --git a/src/test/ui/macros/issue-103529.stderr b/src/test/ui/macros/issue-103529.stderr
new file mode 100644 (file)
index 0000000..61e322a
--- /dev/null
@@ -0,0 +1,39 @@
+error: expected expression, found keyword `mut`
+  --> $DIR/issue-103529.rs:5:6
+   |
+LL | m! { mut x }
+   |      ^^^ expected expression
+
+error: expected a statement
+  --> $DIR/issue-103529.rs:5:10
+   |
+LL |     ($s:stmt) => {}
+   |      ------- while parsing argument for this `stmt` macro fragment
+...
+LL | m! { mut x }
+   |          ^
+
+error: invalid variable declaration
+  --> $DIR/issue-103529.rs:8:6
+   |
+LL | m! { auto x }
+   |      ^^^^
+   |
+help: write `let` instead of `auto` to introduce a new variable
+   |
+LL | m! { let x }
+   |      ~~~
+
+error: invalid variable declaration
+  --> $DIR/issue-103529.rs:10:6
+   |
+LL | m! { var x }
+   |      ^^^
+   |
+help: write `let` instead of `var` to introduce a new variable
+   |
+LL | m! { let x }
+   |      ~~~
+
+error: aborting due to 4 previous errors
+
index 1023189eaa30fc7e43d688bbb6f4a5735182f2fd..36aba8aa08a0b18a95c35a0187a8c569e2e55f8c 100644 (file)
@@ -5,11 +5,13 @@ LL |         assert_eq!("B", "B");
    |         ^^^^^^^^^
 ...
 LL |     foo!()
-   |     ------- help: you might be missing a semicolon here: `;`
-   |     |
-   |     caused by the macro expansion here
+   |     ------ caused by the macro expansion here
    |
    = note: the usage of `foo!` is likely invalid in expression context
+help: you might be missing a semicolon here
+   |
+LL |     foo!();
+   |           +
 
 warning: trailing semicolon in macro used in expression position
   --> $DIR/macro-in-expression-context.rs:5:29
index c153b3b910bbe8dd932341003200db2ca141c731..c42ee9b295e1d365e4f07ff2b76200994470828c 100644 (file)
@@ -7,6 +7,7 @@ LL |                 $token $($inner)? = $value,
 LL | values!(STRING(1) as (String) => cfg(test),);
    | -------------------------------------------- in this macro invocation
    |
+   = help: enum variants can be `Variant`, `Variant = <integer>`, `Variant(Type, ..., TypeN)` or `Variant { fields: Types }`
    = note: this error originates in the macro `values` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: macro expansion ignores token `(String)` and any following
diff --git a/src/test/ui/maximal_mir_to_hir_coverage.rs b/src/test/ui/maximal_mir_to_hir_coverage.rs
new file mode 100644 (file)
index 0000000..5ca5463
--- /dev/null
@@ -0,0 +1,10 @@
+// compile-flags: -Zmaximal-hir-to-mir-coverage
+// run-pass
+
+// Just making sure this flag is accepted and doesn't crash the compiler
+
+fn main() {
+  let x = 1;
+  let y = x + 1;
+  println!("{y}");
+}
index 070cd3054369b686b5f2e5cdb12ccfe78d8cd5e9..8d7b32e025a0864cfb60454c6eb0e2f3b3737de9 100644 (file)
@@ -57,7 +57,7 @@ error[E0308]: mismatched types
   --> $DIR/issue-90315.rs:28:8
    |
 LL |     if 1..(end + 1).is_empty() {
-   |        ^^^^^^^^^^^^^^^^^^^^^^^ expected `bool`, found struct `std::ops::Range`
+   |        ^^^^^^^^^^^^^^^^^^^^^^^ expected `bool`, found struct `Range`
    |
    = note: expected type `bool`
             found struct `std::ops::Range<{integer}>`
@@ -77,7 +77,7 @@ error[E0308]: mismatched types
   --> $DIR/issue-90315.rs:34:8
    |
 LL |     if 1..(end + 1).is_sorted() {
-   |        ^^^^^^^^^^^^^^^^^^^^^^^^ expected `bool`, found struct `std::ops::Range`
+   |        ^^^^^^^^^^^^^^^^^^^^^^^^ expected `bool`, found struct `Range`
    |
    = note: expected type `bool`
             found struct `std::ops::Range<{integer}>`
@@ -97,7 +97,7 @@ error[E0308]: mismatched types
   --> $DIR/issue-90315.rs:40:21
    |
 LL |     let _res: i32 = 3..6.take(2).sum();
-   |               ---   ^^^^^^^^^^^^^^^^^^ expected `i32`, found struct `std::ops::Range`
+   |               ---   ^^^^^^^^^^^^^^^^^^ expected `i32`, found struct `Range`
    |               |
    |               expected due to this
    |
@@ -119,7 +119,7 @@ error[E0308]: mismatched types
   --> $DIR/issue-90315.rs:45:21
    |
 LL |     let _sum: i32 = 3..6.sum();
-   |               ---   ^^^^^^^^^^ expected `i32`, found struct `std::ops::Range`
+   |               ---   ^^^^^^^^^^ expected `i32`, found struct `Range`
    |               |
    |               expected due to this
    |
@@ -158,7 +158,7 @@ error[E0308]: mismatched types
   --> $DIR/issue-90315.rs:62:8
    |
 LL |     if 1..end.error_method() {
-   |        ^^^^^^^^^^^^^^^^^^^^^ expected `bool`, found struct `std::ops::Range`
+   |        ^^^^^^^^^^^^^^^^^^^^^ expected `bool`, found struct `Range`
    |
    = note: expected type `bool`
             found struct `std::ops::Range<{integer}>`
diff --git a/src/test/ui/mir/issue-95978-validator-lifetime-comparison.rs b/src/test/ui/mir/issue-95978-validator-lifetime-comparison.rs
deleted file mode 100644 (file)
index cd6c5bf..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-// check-pass
-// compile-flags: -Zvalidate-mir
-
-fn foo(_a: &str) {}
-
-fn main() {
-    let x = foo as fn(&'static str);
-
-    let _ = x == foo;
-}
index 0ebd20e97d7eff30102f89a8d43150c6c7200b2b..9e04d60198721d3dcced06f6d352ee37ea94f690 100644 (file)
@@ -6,5 +6,5 @@
 fn main() {
     let x = [1, 2, 3];
     // The RHS should coerce to &[i32]
-    let _y : &[i32] = &x : &[i32; 3];
+    let _y : &[i32] = type_ascribe!(&x, &[i32; 3]);
 }
diff --git a/src/test/ui/mir/validate/issue-95978-validator-lifetime-comparison.rs b/src/test/ui/mir/validate/issue-95978-validator-lifetime-comparison.rs
new file mode 100644 (file)
index 0000000..cd6c5bf
--- /dev/null
@@ -0,0 +1,10 @@
+// check-pass
+// compile-flags: -Zvalidate-mir
+
+fn foo(_a: &str) {}
+
+fn main() {
+    let x = foo as fn(&'static str);
+
+    let _ = x == foo;
+}
diff --git a/src/test/ui/mir/validate/needs-reveal-all.rs b/src/test/ui/mir/validate/needs-reveal-all.rs
new file mode 100644 (file)
index 0000000..3852daf
--- /dev/null
@@ -0,0 +1,52 @@
+// Regression test for #105009. the issue here was that even after the `RevealAll` pass,
+// `validate` still used `Reveal::UserFacing`. This meant that it now ends up comparing
+// opaque types with their revealed version, resulting in an ICE.
+//
+// We're using these flags to run the `RevealAll` pass while making it less likely to
+// accidentally removing the assignment from `Foo<fn_ptr>` to `Foo<fn_def>`.
+
+// compile-flags: -Zinline_mir=yes -Zmir-opt-level=0 -Zvalidate-mir
+// run-pass
+
+use std::hint::black_box;
+
+trait Func {
+    type Ret: Id;
+}
+
+trait Id {
+    type Assoc;
+}
+impl Id for u32 {
+    type Assoc = u32;
+}
+impl Id for i32 {
+    type Assoc = i32;
+}
+
+impl<F: FnOnce() -> R, R: Id> Func for F {
+    type Ret = R;
+}
+
+fn bar() -> impl Copy + Id {
+    0u32
+}
+
+struct Foo<T: Func> {
+    _func: T,
+    value: Option<<<T as Func>::Ret as Id>::Assoc>,
+}
+
+fn main() {
+    let mut fn_def = black_box(Foo {
+        _func: bar,
+        value: None,
+    });
+    let fn_ptr = black_box(Foo {
+        _func: bar as fn() -> _,
+        value: None,
+    });
+
+    fn_def.value = fn_ptr.value;
+    black_box(fn_def);
+}
index 3de652d87ec543e27b11ffc2fb7a8e0b35667d0b..3585587ed4c02d6df35458b1aca982bf62b51970 100644 (file)
@@ -24,15 +24,10 @@ LL |     2 as usize - Some(1);
    |
    = help: the trait `Sub<Option<{integer}>>` is not implemented for `usize`
    = help: the following other types implement trait `Sub<Rhs>`:
-             <&'a f32 as Sub<f32>>
-             <&'a f64 as Sub<f64>>
-             <&'a i128 as Sub<i128>>
-             <&'a i16 as Sub<i16>>
-             <&'a i32 as Sub<i32>>
-             <&'a i64 as Sub<i64>>
-             <&'a i8 as Sub<i8>>
-             <&'a isize as Sub<isize>>
-           and 48 others
+             <&'a usize as Sub<usize>>
+             <&usize as Sub<&usize>>
+             <usize as Sub<&usize>>
+             <usize as Sub>
 
 error[E0277]: cannot multiply `{integer}` by `()`
   --> $DIR/binops.rs:4:7
index a02ec819838833dc2920fdc10ea9e5d380f97ba7..a2bf2e8d5b7b330661a6ff1e753bcf7127a076eb 100644 (file)
@@ -130,7 +130,7 @@ note: required by a bound in `map`
   --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
    |
 LL |         F: FnMut(Self::Item) -> B,
-   |            ^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `map`
+   |            ^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Iterator::map`
 
 error[E0593]: closure is expected to take a single 2-tuple as argument, but it takes 3 distinct arguments
   --> $DIR/closure-arg-count.rs:27:57
@@ -146,7 +146,7 @@ note: required by a bound in `map`
   --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
    |
 LL |         F: FnMut(Self::Item) -> B,
-   |            ^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `map`
+   |            ^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Iterator::map`
 
 error[E0593]: function is expected to take a single 2-tuple as argument, but it takes 2 distinct arguments
   --> $DIR/closure-arg-count.rs:29:57
@@ -163,7 +163,7 @@ note: required by a bound in `map`
   --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
    |
 LL |         F: FnMut(Self::Item) -> B,
-   |            ^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `map`
+   |            ^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Iterator::map`
 
 error[E0593]: function is expected to take 1 argument, but it takes 2 arguments
   --> $DIR/closure-arg-count.rs:32:45
@@ -177,7 +177,7 @@ note: required by a bound in `map`
   --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
    |
 LL |         F: FnMut(Self::Item) -> B,
-   |            ^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `map`
+   |            ^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Iterator::map`
 
 error[E0593]: function is expected to take 0 arguments, but it takes 1 argument
   --> $DIR/closure-arg-count.rs:35:10
index 92d545b7366e38a6740788ca4aa1e6de613d58a9..f2e2a4c7fd5fe3671451333ade9f09ed547a89a1 100644 (file)
@@ -12,7 +12,7 @@ note: required by a bound in `map`
   --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
    |
 LL |         F: FnMut(Self::Item) -> B,
-   |            ^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `map`
+   |            ^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Iterator::map`
 
 error[E0631]: type mismatch in closure arguments
   --> $DIR/closure-arg-type-mismatch.rs:4:14
@@ -28,7 +28,7 @@ note: required by a bound in `map`
   --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
    |
 LL |         F: FnMut(Self::Item) -> B,
-   |            ^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `map`
+   |            ^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Iterator::map`
 
 error[E0631]: type mismatch in closure arguments
   --> $DIR/closure-arg-type-mismatch.rs:5:14
@@ -44,7 +44,7 @@ note: required by a bound in `map`
   --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
    |
 LL |         F: FnMut(Self::Item) -> B,
-   |            ^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `map`
+   |            ^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Iterator::map`
 
 error: aborting due to 3 previous errors
 
index 906001ca1e09ee026b7d5fef1f02482310244bc4..b3509abbf84eb9a1841125543b1094e404fd48d3 100644 (file)
@@ -12,7 +12,7 @@ note: required by a bound in `filter`
   --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
    |
 LL |         P: FnMut(&Self::Item) -> bool,
-   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `filter`
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Iterator::filter`
 
 error[E0599]: the method `count` exists for struct `Filter<Fuse<std::iter::Once<&str>>, [closure@$DIR/issue-36053-2.rs:7:39: 7:48]>`, but its trait bounds were not satisfied
   --> $DIR/issue-36053-2.rs:7:55
index e8eb8d263ec795d068e71d14ef464dc56020a7e4..fdd92cbfc44370ba06c3c492ca72851eb9c5b294 100644 (file)
@@ -42,7 +42,7 @@ error[E0308]: mismatched types
   --> $DIR/wrap-suggestion-privacy.rs:22:17
    |
 LL |     needs_ready(Some(0));
-   |     ----------- ^^^^^^^ expected struct `std::future::Ready`, found enum `Option`
+   |     ----------- ^^^^^^^ expected struct `Ready`, found enum `Option`
    |     |
    |     arguments to this function are incorrect
    |
index fed780e68957f903a1ca1cb77e8308e627354620..2d22da0b420e0b171ebf5af60d1dd56660cf2d47 100644 (file)
@@ -6,15 +6,10 @@ LL |     2_usize + (loop {});
    |
    = help: the trait `Add<()>` is not implemented for `usize`
    = 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
+             <&'a usize as Add<usize>>
+             <&usize as Add<&usize>>
+             <usize as Add<&usize>>
+             <usize as Add>
 
 error: aborting due to previous error
 
index 9b3ec702c75da600c3ddb31a1fa2aa5e8320febe..95c655654eaa4e550f7d1a195a8523a3775d8011 100644 (file)
@@ -8,17 +8,17 @@
 type PairCoupledRegions<'a, T> = (&'a T, &'a T);
 
 fn uncoupled_wilds_rhs<'a>(_x: &'a u32, s: &'static u32) -> &'static u32 {
-    let ((y, _z),) = ((s, _x),): (PairUncoupled<_>,);
+    let ((y, _z),) = type_ascribe!(((s, _x),), (PairUncoupled<_>,));
     y // OK
 }
 
 fn coupled_wilds_rhs<'a>(_x: &'a u32, s: &'static u32) -> &'static u32 {
-    let ((y, _z),) = ((s, _x),): (PairCoupledTypes<_>,);
+    let ((y, _z),) = type_ascribe!(((s, _x),), (PairCoupledTypes<_>,));
     y //~ ERROR lifetime may not live long enough
 }
 
 fn coupled_regions_rhs<'a>(_x: &'a u32, s: &'static u32) -> &'static u32 {
-    let ((y, _z),) = ((s, _x),): (PairCoupledRegions<_>,);
+    let ((y, _z),) = type_ascribe!(((s, _x),), (PairCoupledRegions<_>,));
     y //~ ERROR lifetime may not live long enough
 }
 
index c99f53c5aa4c58db0c188b768fe39c2ab4bc053f..8601691e88ad7a0381534f66da462e6d77ff4a5c 100644 (file)
@@ -3,7 +3,7 @@ error: lifetime may not live long enough
    |
 LL | fn coupled_wilds_rhs<'a>(_x: &'a u32, s: &'static u32) -> &'static u32 {
    |                      -- lifetime `'a` defined here
-LL |     let ((y, _z),) = ((s, _x),): (PairCoupledTypes<_>,);
+LL |     let ((y, _z),) = type_ascribe!(((s, _x),), (PairCoupledTypes<_>,));
 LL |     y
    |     ^ returning this value requires that `'a` must outlive `'static`
 
@@ -12,7 +12,7 @@ error: lifetime may not live long enough
    |
 LL | fn coupled_regions_rhs<'a>(_x: &'a u32, s: &'static u32) -> &'static u32 {
    |                        -- lifetime `'a` defined here
-LL |     let ((y, _z),) = ((s, _x),): (PairCoupledRegions<_>,);
+LL |     let ((y, _z),) = type_ascribe!(((s, _x),), (PairCoupledRegions<_>,));
 LL |     y
    |     ^ returning this value requires that `'a` must outlive `'static`
 
index 101b5cfabb3d06419e37559c583179c4b15f5790..88d646dee7c74ab5c0a3a86784a877015f405d91 100644 (file)
@@ -3,5 +3,5 @@
 
 fn main() {
     let x = 22_u32;
-    let y: &u32 = &x: &'static u32; //~ ERROR E0597
+    let y: &u32 = type_ascribe!(&x, &'static u32); //~ ERROR E0597
 }
index 133bbef52311dc1135ea0faf821e4619383161f3..ccbf3c1d927c6b02e29571a8645a45b8458df656 100644 (file)
@@ -1,10 +1,10 @@
 error[E0597]: `x` does not live long enough
-  --> $DIR/type_ascription_static_lifetime.rs:6:19
+  --> $DIR/type_ascription_static_lifetime.rs:6:33
    |
-LL |     let y: &u32 = &x: &'static u32;
-   |                   ^^--------------
-   |                   |
-   |                   borrowed value does not live long enough
+LL |     let y: &u32 = type_ascribe!(&x, &'static u32);
+   |                   --------------^^---------------
+   |                   |             |
+   |                   |             borrowed value does not live long enough
    |                   type annotation requires that `x` is borrowed for `'static`
 LL | }
    | - `x` dropped here while still borrowed
index 6aa1ad8dd899f906dbcc5d85ae64b0f299b1b3c3..8f0eef237cfe216601efbfadc2be0f0c770e32b7 100644 (file)
@@ -6,15 +6,10 @@ LL |     x + 100.0
    |
    = help: the trait `Add<{float}>` is not implemented for `u8`
    = 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
+             <&'a u8 as Add<u8>>
+             <&u8 as Add<&u8>>
+             <u8 as Add<&u8>>
+             <u8 as Add>
 
 error[E0277]: cannot add `&str` to `f64`
   --> $DIR/not-suggest-float-literal.rs:6:7
@@ -24,15 +19,10 @@ LL |     x + "foo"
    |
    = help: the trait `Add<&str>` is not implemented for `f64`
    = 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
+             <&f64 as Add<&f64>>
+             <f64 as Add<&f64>>
+             <f64 as Add>
 
 error[E0277]: cannot add `{integer}` to `f64`
   --> $DIR/not-suggest-float-literal.rs:11:7
@@ -42,15 +32,10 @@ LL |     x + y
    |
    = help: the trait `Add<{integer}>` is not implemented for `f64`
    = 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
+             <&f64 as Add<&f64>>
+             <f64 as Add<&f64>>
+             <f64 as Add>
 
 error[E0277]: cannot subtract `{float}` from `u8`
   --> $DIR/not-suggest-float-literal.rs:15:7
@@ -60,15 +45,10 @@ LL |     x - 100.0
    |
    = help: the trait `Sub<{float}>` is not implemented for `u8`
    = help: the following other types implement trait `Sub<Rhs>`:
-             <&'a f32 as Sub<f32>>
-             <&'a f64 as Sub<f64>>
-             <&'a i128 as Sub<i128>>
-             <&'a i16 as Sub<i16>>
-             <&'a i32 as Sub<i32>>
-             <&'a i64 as Sub<i64>>
-             <&'a i8 as Sub<i8>>
-             <&'a isize as Sub<isize>>
-           and 48 others
+             <&'a u8 as Sub<u8>>
+             <&u8 as Sub<&u8>>
+             <u8 as Sub<&u8>>
+             <u8 as Sub>
 
 error[E0277]: cannot subtract `&str` from `f64`
   --> $DIR/not-suggest-float-literal.rs:19:7
@@ -78,15 +58,10 @@ LL |     x - "foo"
    |
    = help: the trait `Sub<&str>` is not implemented for `f64`
    = help: the following other types implement trait `Sub<Rhs>`:
-             <&'a f32 as Sub<f32>>
              <&'a f64 as Sub<f64>>
-             <&'a i128 as Sub<i128>>
-             <&'a i16 as Sub<i16>>
-             <&'a i32 as Sub<i32>>
-             <&'a i64 as Sub<i64>>
-             <&'a i8 as Sub<i8>>
-             <&'a isize as Sub<isize>>
-           and 48 others
+             <&f64 as Sub<&f64>>
+             <f64 as Sub<&f64>>
+             <f64 as Sub>
 
 error[E0277]: cannot subtract `{integer}` from `f64`
   --> $DIR/not-suggest-float-literal.rs:24:7
@@ -96,15 +71,10 @@ LL |     x - y
    |
    = help: the trait `Sub<{integer}>` is not implemented for `f64`
    = help: the following other types implement trait `Sub<Rhs>`:
-             <&'a f32 as Sub<f32>>
              <&'a f64 as Sub<f64>>
-             <&'a i128 as Sub<i128>>
-             <&'a i16 as Sub<i16>>
-             <&'a i32 as Sub<i32>>
-             <&'a i64 as Sub<i64>>
-             <&'a i8 as Sub<i8>>
-             <&'a isize as Sub<isize>>
-           and 48 others
+             <&f64 as Sub<&f64>>
+             <f64 as Sub<&f64>>
+             <f64 as Sub>
 
 error[E0277]: cannot multiply `u8` by `{float}`
   --> $DIR/not-suggest-float-literal.rs:28:7
@@ -114,15 +84,10 @@ LL |     x * 100.0
    |
    = help: the trait `Mul<{float}>` is not implemented for `u8`
    = help: the following other types implement trait `Mul<Rhs>`:
-             <&'a f32 as Mul<f32>>
-             <&'a f64 as Mul<f64>>
-             <&'a i128 as Mul<i128>>
-             <&'a i16 as Mul<i16>>
-             <&'a i32 as Mul<i32>>
-             <&'a i64 as Mul<i64>>
-             <&'a i8 as Mul<i8>>
-             <&'a isize as Mul<isize>>
-           and 49 others
+             <&'a u8 as Mul<u8>>
+             <&u8 as Mul<&u8>>
+             <u8 as Mul<&u8>>
+             <u8 as Mul>
 
 error[E0277]: cannot multiply `f64` by `&str`
   --> $DIR/not-suggest-float-literal.rs:32:7
@@ -132,15 +97,10 @@ LL |     x * "foo"
    |
    = help: the trait `Mul<&str>` is not implemented for `f64`
    = help: the following other types implement trait `Mul<Rhs>`:
-             <&'a f32 as Mul<f32>>
              <&'a f64 as Mul<f64>>
-             <&'a i128 as Mul<i128>>
-             <&'a i16 as Mul<i16>>
-             <&'a i32 as Mul<i32>>
-             <&'a i64 as Mul<i64>>
-             <&'a i8 as Mul<i8>>
-             <&'a isize as Mul<isize>>
-           and 49 others
+             <&f64 as Mul<&f64>>
+             <f64 as Mul<&f64>>
+             <f64 as Mul>
 
 error[E0277]: cannot multiply `f64` by `{integer}`
   --> $DIR/not-suggest-float-literal.rs:37:7
@@ -150,15 +110,10 @@ LL |     x * y
    |
    = help: the trait `Mul<{integer}>` is not implemented for `f64`
    = help: the following other types implement trait `Mul<Rhs>`:
-             <&'a f32 as Mul<f32>>
              <&'a f64 as Mul<f64>>
-             <&'a i128 as Mul<i128>>
-             <&'a i16 as Mul<i16>>
-             <&'a i32 as Mul<i32>>
-             <&'a i64 as Mul<i64>>
-             <&'a i8 as Mul<i8>>
-             <&'a isize as Mul<isize>>
-           and 49 others
+             <&f64 as Mul<&f64>>
+             <f64 as Mul<&f64>>
+             <f64 as Mul>
 
 error[E0277]: cannot divide `u8` by `{float}`
   --> $DIR/not-suggest-float-literal.rs:41:7
@@ -168,15 +123,11 @@ LL |     x / 100.0
    |
    = help: the trait `Div<{float}>` is not implemented for `u8`
    = help: the following other types implement trait `Div<Rhs>`:
-             <&'a f32 as Div<f32>>
-             <&'a f64 as Div<f64>>
-             <&'a i128 as Div<i128>>
-             <&'a i16 as Div<i16>>
-             <&'a i32 as Div<i32>>
-             <&'a i64 as Div<i64>>
-             <&'a i8 as Div<i8>>
-             <&'a isize as Div<isize>>
-           and 54 others
+             <&'a u8 as Div<u8>>
+             <&u8 as Div<&u8>>
+             <u8 as Div<&u8>>
+             <u8 as Div<NonZeroU8>>
+             <u8 as Div>
 
 error[E0277]: cannot divide `f64` by `&str`
   --> $DIR/not-suggest-float-literal.rs:45:7
@@ -186,15 +137,10 @@ LL |     x / "foo"
    |
    = help: the trait `Div<&str>` is not implemented for `f64`
    = help: the following other types implement trait `Div<Rhs>`:
-             <&'a f32 as Div<f32>>
              <&'a f64 as Div<f64>>
-             <&'a i128 as Div<i128>>
-             <&'a i16 as Div<i16>>
-             <&'a i32 as Div<i32>>
-             <&'a i64 as Div<i64>>
-             <&'a i8 as Div<i8>>
-             <&'a isize as Div<isize>>
-           and 54 others
+             <&f64 as Div<&f64>>
+             <f64 as Div<&f64>>
+             <f64 as Div>
 
 error[E0277]: cannot divide `f64` by `{integer}`
   --> $DIR/not-suggest-float-literal.rs:50:7
@@ -204,15 +150,10 @@ LL |     x / y
    |
    = help: the trait `Div<{integer}>` is not implemented for `f64`
    = help: the following other types implement trait `Div<Rhs>`:
-             <&'a f32 as Div<f32>>
              <&'a f64 as Div<f64>>
-             <&'a i128 as Div<i128>>
-             <&'a i16 as Div<i16>>
-             <&'a i32 as Div<i32>>
-             <&'a i64 as Div<i64>>
-             <&'a i8 as Div<i8>>
-             <&'a isize as Div<isize>>
-           and 54 others
+             <&f64 as Div<&f64>>
+             <f64 as Div<&f64>>
+             <f64 as Div>
 
 error: aborting due to 12 previous errors
 
index 988379e582a3476779d295890e952c1eca0c752a..03779d356371aacb52800360d926570ee4b8ea51 100644 (file)
@@ -7,14 +7,9 @@ LL |     x + 100
    = help: the trait `Add<{integer}>` is not implemented for `f32`
    = 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
+             <&f32 as Add<&f32>>
+             <f32 as Add<&f32>>
+             <f32 as Add>
 help: consider using a floating-point literal by writing it with `.0`
    |
 LL |     x + 100.0
@@ -28,15 +23,10 @@ LL |     x + 100
    |
    = help: the trait `Add<{integer}>` is not implemented for `f64`
    = 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
+             <&f64 as Add<&f64>>
+             <f64 as Add<&f64>>
+             <f64 as Add>
 help: consider using a floating-point literal by writing it with `.0`
    |
 LL |     x + 100.0
@@ -51,14 +41,9 @@ LL |     x - 100
    = help: the trait `Sub<{integer}>` is not implemented for `f32`
    = help: the following other types implement trait `Sub<Rhs>`:
              <&'a f32 as Sub<f32>>
-             <&'a f64 as Sub<f64>>
-             <&'a i128 as Sub<i128>>
-             <&'a i16 as Sub<i16>>
-             <&'a i32 as Sub<i32>>
-             <&'a i64 as Sub<i64>>
-             <&'a i8 as Sub<i8>>
-             <&'a isize as Sub<isize>>
-           and 48 others
+             <&f32 as Sub<&f32>>
+             <f32 as Sub<&f32>>
+             <f32 as Sub>
 help: consider using a floating-point literal by writing it with `.0`
    |
 LL |     x - 100.0
@@ -72,15 +57,10 @@ LL |     x - 100
    |
    = help: the trait `Sub<{integer}>` is not implemented for `f64`
    = help: the following other types implement trait `Sub<Rhs>`:
-             <&'a f32 as Sub<f32>>
              <&'a f64 as Sub<f64>>
-             <&'a i128 as Sub<i128>>
-             <&'a i16 as Sub<i16>>
-             <&'a i32 as Sub<i32>>
-             <&'a i64 as Sub<i64>>
-             <&'a i8 as Sub<i8>>
-             <&'a isize as Sub<isize>>
-           and 48 others
+             <&f64 as Sub<&f64>>
+             <f64 as Sub<&f64>>
+             <f64 as Sub>
 help: consider using a floating-point literal by writing it with `.0`
    |
 LL |     x - 100.0
@@ -95,14 +75,9 @@ LL |     x * 100
    = help: the trait `Mul<{integer}>` is not implemented for `f32`
    = help: the following other types implement trait `Mul<Rhs>`:
              <&'a f32 as Mul<f32>>
-             <&'a f64 as Mul<f64>>
-             <&'a i128 as Mul<i128>>
-             <&'a i16 as Mul<i16>>
-             <&'a i32 as Mul<i32>>
-             <&'a i64 as Mul<i64>>
-             <&'a i8 as Mul<i8>>
-             <&'a isize as Mul<isize>>
-           and 49 others
+             <&f32 as Mul<&f32>>
+             <f32 as Mul<&f32>>
+             <f32 as Mul>
 help: consider using a floating-point literal by writing it with `.0`
    |
 LL |     x * 100.0
@@ -116,15 +91,10 @@ LL |     x * 100
    |
    = help: the trait `Mul<{integer}>` is not implemented for `f64`
    = help: the following other types implement trait `Mul<Rhs>`:
-             <&'a f32 as Mul<f32>>
              <&'a f64 as Mul<f64>>
-             <&'a i128 as Mul<i128>>
-             <&'a i16 as Mul<i16>>
-             <&'a i32 as Mul<i32>>
-             <&'a i64 as Mul<i64>>
-             <&'a i8 as Mul<i8>>
-             <&'a isize as Mul<isize>>
-           and 49 others
+             <&f64 as Mul<&f64>>
+             <f64 as Mul<&f64>>
+             <f64 as Mul>
 help: consider using a floating-point literal by writing it with `.0`
    |
 LL |     x * 100.0
@@ -139,14 +109,9 @@ LL |     x / 100
    = help: the trait `Div<{integer}>` is not implemented for `f32`
    = help: the following other types implement trait `Div<Rhs>`:
              <&'a f32 as Div<f32>>
-             <&'a f64 as Div<f64>>
-             <&'a i128 as Div<i128>>
-             <&'a i16 as Div<i16>>
-             <&'a i32 as Div<i32>>
-             <&'a i64 as Div<i64>>
-             <&'a i8 as Div<i8>>
-             <&'a isize as Div<isize>>
-           and 54 others
+             <&f32 as Div<&f32>>
+             <f32 as Div<&f32>>
+             <f32 as Div>
 help: consider using a floating-point literal by writing it with `.0`
    |
 LL |     x / 100.0
@@ -160,15 +125,10 @@ LL |     x / 100
    |
    = help: the trait `Div<{integer}>` is not implemented for `f64`
    = help: the following other types implement trait `Div<Rhs>`:
-             <&'a f32 as Div<f32>>
              <&'a f64 as Div<f64>>
-             <&'a i128 as Div<i128>>
-             <&'a i16 as Div<i16>>
-             <&'a i32 as Div<i32>>
-             <&'a i64 as Div<i64>>
-             <&'a i8 as Div<i8>>
-             <&'a isize as Div<isize>>
-           and 54 others
+             <&f64 as Div<&f64>>
+             <f64 as Div<&f64>>
+             <f64 as Div>
 help: consider using a floating-point literal by writing it with `.0`
    |
 LL |     x / 100.0
index 2f58f164985db92b3fd4f5b8c2b8802c4c902c65..d5213e3f5b690d757baa39a21bcdd17b62f97195 100644 (file)
@@ -2,7 +2,9 @@ error[E0308]: mismatched types
   --> $DIR/numeric-cast-binop.rs:23:16
    |
 LL |         x_u8 > x_u16;
-   |                ^^^^^ expected `u8`, found `u16`
+   |         ----   ^^^^^ expected `u8`, found `u16`
+   |         |
+   |         expected because this is `u8`
    |
 help: you can convert `x_u8` from `u8` to `u16`, matching the type of `x_u16`
    |
@@ -13,7 +15,9 @@ error[E0308]: mismatched types
   --> $DIR/numeric-cast-binop.rs:25:16
    |
 LL |         x_u8 > x_u32;
-   |                ^^^^^ expected `u8`, found `u32`
+   |         ----   ^^^^^ expected `u8`, found `u32`
+   |         |
+   |         expected because this is `u8`
    |
 help: you can convert `x_u8` from `u8` to `u32`, matching the type of `x_u32`
    |
@@ -24,7 +28,9 @@ error[E0308]: mismatched types
   --> $DIR/numeric-cast-binop.rs:27:16
    |
 LL |         x_u8 > x_u64;
-   |                ^^^^^ expected `u8`, found `u64`
+   |         ----   ^^^^^ expected `u8`, found `u64`
+   |         |
+   |         expected because this is `u8`
    |
 help: you can convert `x_u8` from `u8` to `u64`, matching the type of `x_u64`
    |
@@ -35,7 +41,9 @@ error[E0308]: mismatched types
   --> $DIR/numeric-cast-binop.rs:29:16
    |
 LL |         x_u8 > x_u128;
-   |                ^^^^^^ expected `u8`, found `u128`
+   |         ----   ^^^^^^ expected `u8`, found `u128`
+   |         |
+   |         expected because this is `u8`
    |
 help: you can convert `x_u8` from `u8` to `u128`, matching the type of `x_u128`
    |
@@ -46,7 +54,9 @@ error[E0308]: mismatched types
   --> $DIR/numeric-cast-binop.rs:31:16
    |
 LL |         x_u8 > x_usize;
-   |                ^^^^^^^ expected `u8`, found `usize`
+   |         ----   ^^^^^^^ expected `u8`, found `usize`
+   |         |
+   |         expected because this is `u8`
    |
 help: you can convert `x_u8` from `u8` to `usize`, matching the type of `x_usize`
    |
@@ -57,7 +67,9 @@ error[E0308]: mismatched types
   --> $DIR/numeric-cast-binop.rs:34:17
    |
 LL |         x_u16 > x_u8;
-   |                 ^^^^ expected `u16`, found `u8`
+   |         -----   ^^^^ expected `u16`, found `u8`
+   |         |
+   |         expected because this is `u16`
    |
 help: you can convert a `u8` to a `u16`
    |
@@ -68,7 +80,9 @@ error[E0308]: mismatched types
   --> $DIR/numeric-cast-binop.rs:36:17
    |
 LL |         x_u16 > x_u32;
-   |                 ^^^^^ expected `u16`, found `u32`
+   |         -----   ^^^^^ expected `u16`, found `u32`
+   |         |
+   |         expected because this is `u16`
    |
 help: you can convert `x_u16` from `u16` to `u32`, matching the type of `x_u32`
    |
@@ -79,7 +93,9 @@ error[E0308]: mismatched types
   --> $DIR/numeric-cast-binop.rs:38:17
    |
 LL |         x_u16 > x_u64;
-   |                 ^^^^^ expected `u16`, found `u64`
+   |         -----   ^^^^^ expected `u16`, found `u64`
+   |         |
+   |         expected because this is `u16`
    |
 help: you can convert `x_u16` from `u16` to `u64`, matching the type of `x_u64`
    |
@@ -90,7 +106,9 @@ error[E0308]: mismatched types
   --> $DIR/numeric-cast-binop.rs:40:17
    |
 LL |         x_u16 > x_u128;
-   |                 ^^^^^^ expected `u16`, found `u128`
+   |         -----   ^^^^^^ expected `u16`, found `u128`
+   |         |
+   |         expected because this is `u16`
    |
 help: you can convert `x_u16` from `u16` to `u128`, matching the type of `x_u128`
    |
@@ -101,7 +119,9 @@ error[E0308]: mismatched types
   --> $DIR/numeric-cast-binop.rs:42:17
    |
 LL |         x_u16 > x_usize;
-   |                 ^^^^^^^ expected `u16`, found `usize`
+   |         -----   ^^^^^^^ expected `u16`, found `usize`
+   |         |
+   |         expected because this is `u16`
    |
 help: you can convert `x_u16` from `u16` to `usize`, matching the type of `x_usize`
    |
@@ -112,7 +132,9 @@ error[E0308]: mismatched types
   --> $DIR/numeric-cast-binop.rs:45:17
    |
 LL |         x_u32 > x_u8;
-   |                 ^^^^ expected `u32`, found `u8`
+   |         -----   ^^^^ expected `u32`, found `u8`
+   |         |
+   |         expected because this is `u32`
    |
 help: you can convert a `u8` to a `u32`
    |
@@ -123,7 +145,9 @@ error[E0308]: mismatched types
   --> $DIR/numeric-cast-binop.rs:47:17
    |
 LL |         x_u32 > x_u16;
-   |                 ^^^^^ expected `u32`, found `u16`
+   |         -----   ^^^^^ expected `u32`, found `u16`
+   |         |
+   |         expected because this is `u32`
    |
 help: you can convert a `u16` to a `u32`
    |
@@ -134,7 +158,9 @@ error[E0308]: mismatched types
   --> $DIR/numeric-cast-binop.rs:49:17
    |
 LL |         x_u32 > x_u64;
-   |                 ^^^^^ expected `u32`, found `u64`
+   |         -----   ^^^^^ expected `u32`, found `u64`
+   |         |
+   |         expected because this is `u32`
    |
 help: you can convert `x_u32` from `u32` to `u64`, matching the type of `x_u64`
    |
@@ -145,7 +171,9 @@ error[E0308]: mismatched types
   --> $DIR/numeric-cast-binop.rs:51:17
    |
 LL |         x_u32 > x_u128;
-   |                 ^^^^^^ expected `u32`, found `u128`
+   |         -----   ^^^^^^ expected `u32`, found `u128`
+   |         |
+   |         expected because this is `u32`
    |
 help: you can convert `x_u32` from `u32` to `u128`, matching the type of `x_u128`
    |
@@ -156,7 +184,9 @@ error[E0308]: mismatched types
   --> $DIR/numeric-cast-binop.rs:53:17
    |
 LL |         x_u32 > x_usize;
-   |                 ^^^^^^^ expected `u32`, found `usize`
+   |         -----   ^^^^^^^ expected `u32`, found `usize`
+   |         |
+   |         expected because this is `u32`
    |
 help: you can convert a `usize` to a `u32` and panic if the converted value doesn't fit
    |
@@ -167,7 +197,9 @@ error[E0308]: mismatched types
   --> $DIR/numeric-cast-binop.rs:56:17
    |
 LL |         x_u64 > x_u8;
-   |                 ^^^^ expected `u64`, found `u8`
+   |         -----   ^^^^ expected `u64`, found `u8`
+   |         |
+   |         expected because this is `u64`
    |
 help: you can convert a `u8` to a `u64`
    |
@@ -178,7 +210,9 @@ error[E0308]: mismatched types
   --> $DIR/numeric-cast-binop.rs:58:17
    |
 LL |         x_u64 > x_u16;
-   |                 ^^^^^ expected `u64`, found `u16`
+   |         -----   ^^^^^ expected `u64`, found `u16`
+   |         |
+   |         expected because this is `u64`
    |
 help: you can convert a `u16` to a `u64`
    |
@@ -189,7 +223,9 @@ error[E0308]: mismatched types
   --> $DIR/numeric-cast-binop.rs:60:17
    |
 LL |         x_u64 > x_u32;
-   |                 ^^^^^ expected `u64`, found `u32`
+   |         -----   ^^^^^ expected `u64`, found `u32`
+   |         |
+   |         expected because this is `u64`
    |
 help: you can convert a `u32` to a `u64`
    |
@@ -200,7 +236,9 @@ error[E0308]: mismatched types
   --> $DIR/numeric-cast-binop.rs:62:17
    |
 LL |         x_u64 > x_u128;
-   |                 ^^^^^^ expected `u64`, found `u128`
+   |         -----   ^^^^^^ expected `u64`, found `u128`
+   |         |
+   |         expected because this is `u64`
    |
 help: you can convert `x_u64` from `u64` to `u128`, matching the type of `x_u128`
    |
@@ -211,7 +249,9 @@ error[E0308]: mismatched types
   --> $DIR/numeric-cast-binop.rs:64:17
    |
 LL |         x_u64 > x_usize;
-   |                 ^^^^^^^ expected `u64`, found `usize`
+   |         -----   ^^^^^^^ expected `u64`, found `usize`
+   |         |
+   |         expected because this is `u64`
    |
 help: you can convert a `usize` to a `u64` and panic if the converted value doesn't fit
    |
@@ -222,7 +262,9 @@ error[E0308]: mismatched types
   --> $DIR/numeric-cast-binop.rs:67:18
    |
 LL |         x_u128 > x_u8;
-   |                  ^^^^ expected `u128`, found `u8`
+   |         ------   ^^^^ expected `u128`, found `u8`
+   |         |
+   |         expected because this is `u128`
    |
 help: you can convert a `u8` to a `u128`
    |
@@ -233,7 +275,9 @@ error[E0308]: mismatched types
   --> $DIR/numeric-cast-binop.rs:69:18
    |
 LL |         x_u128 > x_u16;
-   |                  ^^^^^ expected `u128`, found `u16`
+   |         ------   ^^^^^ expected `u128`, found `u16`
+   |         |
+   |         expected because this is `u128`
    |
 help: you can convert a `u16` to a `u128`
    |
@@ -244,7 +288,9 @@ error[E0308]: mismatched types
   --> $DIR/numeric-cast-binop.rs:71:18
    |
 LL |         x_u128 > x_u32;
-   |                  ^^^^^ expected `u128`, found `u32`
+   |         ------   ^^^^^ expected `u128`, found `u32`
+   |         |
+   |         expected because this is `u128`
    |
 help: you can convert a `u32` to a `u128`
    |
@@ -255,7 +301,9 @@ error[E0308]: mismatched types
   --> $DIR/numeric-cast-binop.rs:73:18
    |
 LL |         x_u128 > x_u64;
-   |                  ^^^^^ expected `u128`, found `u64`
+   |         ------   ^^^^^ expected `u128`, found `u64`
+   |         |
+   |         expected because this is `u128`
    |
 help: you can convert a `u64` to a `u128`
    |
@@ -266,7 +314,9 @@ error[E0308]: mismatched types
   --> $DIR/numeric-cast-binop.rs:75:18
    |
 LL |         x_u128 > x_usize;
-   |                  ^^^^^^^ expected `u128`, found `usize`
+   |         ------   ^^^^^^^ expected `u128`, found `usize`
+   |         |
+   |         expected because this is `u128`
    |
 help: you can convert a `usize` to a `u128` and panic if the converted value doesn't fit
    |
@@ -277,7 +327,9 @@ error[E0308]: mismatched types
   --> $DIR/numeric-cast-binop.rs:78:19
    |
 LL |         x_usize > x_u8;
-   |                   ^^^^ expected `usize`, found `u8`
+   |         -------   ^^^^ expected `usize`, found `u8`
+   |         |
+   |         expected because this is `usize`
    |
 help: you can convert a `u8` to a `usize`
    |
@@ -288,7 +340,9 @@ error[E0308]: mismatched types
   --> $DIR/numeric-cast-binop.rs:80:19
    |
 LL |         x_usize > x_u16;
-   |                   ^^^^^ expected `usize`, found `u16`
+   |         -------   ^^^^^ expected `usize`, found `u16`
+   |         |
+   |         expected because this is `usize`
    |
 help: you can convert a `u16` to a `usize`
    |
@@ -299,7 +353,9 @@ error[E0308]: mismatched types
   --> $DIR/numeric-cast-binop.rs:82:19
    |
 LL |         x_usize > x_u32;
-   |                   ^^^^^ expected `usize`, found `u32`
+   |         -------   ^^^^^ expected `usize`, found `u32`
+   |         |
+   |         expected because this is `usize`
    |
 help: you can convert a `u32` to a `usize` and panic if the converted value doesn't fit
    |
@@ -310,7 +366,9 @@ error[E0308]: mismatched types
   --> $DIR/numeric-cast-binop.rs:84:19
    |
 LL |         x_usize > x_u64;
-   |                   ^^^^^ expected `usize`, found `u64`
+   |         -------   ^^^^^ expected `usize`, found `u64`
+   |         |
+   |         expected because this is `usize`
    |
 help: you can convert a `u64` to a `usize` and panic if the converted value doesn't fit
    |
@@ -321,7 +379,9 @@ error[E0308]: mismatched types
   --> $DIR/numeric-cast-binop.rs:86:19
    |
 LL |         x_usize > x_u128;
-   |                   ^^^^^^ expected `usize`, found `u128`
+   |         -------   ^^^^^^ expected `usize`, found `u128`
+   |         |
+   |         expected because this is `usize`
    |
 help: you can convert a `u128` to a `usize` and panic if the converted value doesn't fit
    |
@@ -332,7 +392,9 @@ error[E0308]: mismatched types
   --> $DIR/numeric-cast-binop.rs:92:16
    |
 LL |         x_i8 > x_i16;
-   |                ^^^^^ expected `i8`, found `i16`
+   |         ----   ^^^^^ expected `i8`, found `i16`
+   |         |
+   |         expected because this is `i8`
    |
 help: you can convert `x_i8` from `i8` to `i16`, matching the type of `x_i16`
    |
@@ -343,7 +405,9 @@ error[E0308]: mismatched types
   --> $DIR/numeric-cast-binop.rs:94:16
    |
 LL |         x_i8 > x_i32;
-   |                ^^^^^ expected `i8`, found `i32`
+   |         ----   ^^^^^ expected `i8`, found `i32`
+   |         |
+   |         expected because this is `i8`
    |
 help: you can convert `x_i8` from `i8` to `i32`, matching the type of `x_i32`
    |
@@ -354,7 +418,9 @@ error[E0308]: mismatched types
   --> $DIR/numeric-cast-binop.rs:96:16
    |
 LL |         x_i8 > x_i64;
-   |                ^^^^^ expected `i8`, found `i64`
+   |         ----   ^^^^^ expected `i8`, found `i64`
+   |         |
+   |         expected because this is `i8`
    |
 help: you can convert `x_i8` from `i8` to `i64`, matching the type of `x_i64`
    |
@@ -365,7 +431,9 @@ error[E0308]: mismatched types
   --> $DIR/numeric-cast-binop.rs:98:16
    |
 LL |         x_i8 > x_i128;
-   |                ^^^^^^ expected `i8`, found `i128`
+   |         ----   ^^^^^^ expected `i8`, found `i128`
+   |         |
+   |         expected because this is `i8`
    |
 help: you can convert `x_i8` from `i8` to `i128`, matching the type of `x_i128`
    |
@@ -376,7 +444,9 @@ error[E0308]: mismatched types
   --> $DIR/numeric-cast-binop.rs:100:16
    |
 LL |         x_i8 > x_isize;
-   |                ^^^^^^^ expected `i8`, found `isize`
+   |         ----   ^^^^^^^ expected `i8`, found `isize`
+   |         |
+   |         expected because this is `i8`
    |
 help: you can convert `x_i8` from `i8` to `isize`, matching the type of `x_isize`
    |
@@ -387,7 +457,9 @@ error[E0308]: mismatched types
   --> $DIR/numeric-cast-binop.rs:103:17
    |
 LL |         x_i16 > x_i8;
-   |                 ^^^^ expected `i16`, found `i8`
+   |         -----   ^^^^ expected `i16`, found `i8`
+   |         |
+   |         expected because this is `i16`
    |
 help: you can convert an `i8` to an `i16`
    |
@@ -398,7 +470,9 @@ error[E0308]: mismatched types
   --> $DIR/numeric-cast-binop.rs:105:17
    |
 LL |         x_i16 > x_i32;
-   |                 ^^^^^ expected `i16`, found `i32`
+   |         -----   ^^^^^ expected `i16`, found `i32`
+   |         |
+   |         expected because this is `i16`
    |
 help: you can convert `x_i16` from `i16` to `i32`, matching the type of `x_i32`
    |
@@ -409,7 +483,9 @@ error[E0308]: mismatched types
   --> $DIR/numeric-cast-binop.rs:107:17
    |
 LL |         x_i16 > x_i64;
-   |                 ^^^^^ expected `i16`, found `i64`
+   |         -----   ^^^^^ expected `i16`, found `i64`
+   |         |
+   |         expected because this is `i16`
    |
 help: you can convert `x_i16` from `i16` to `i64`, matching the type of `x_i64`
    |
@@ -420,7 +496,9 @@ error[E0308]: mismatched types
   --> $DIR/numeric-cast-binop.rs:109:17
    |
 LL |         x_i16 > x_i128;
-   |                 ^^^^^^ expected `i16`, found `i128`
+   |         -----   ^^^^^^ expected `i16`, found `i128`
+   |         |
+   |         expected because this is `i16`
    |
 help: you can convert `x_i16` from `i16` to `i128`, matching the type of `x_i128`
    |
@@ -431,7 +509,9 @@ error[E0308]: mismatched types
   --> $DIR/numeric-cast-binop.rs:111:17
    |
 LL |         x_i16 > x_isize;
-   |                 ^^^^^^^ expected `i16`, found `isize`
+   |         -----   ^^^^^^^ expected `i16`, found `isize`
+   |         |
+   |         expected because this is `i16`
    |
 help: you can convert `x_i16` from `i16` to `isize`, matching the type of `x_isize`
    |
@@ -442,7 +522,9 @@ error[E0308]: mismatched types
   --> $DIR/numeric-cast-binop.rs:114:17
    |
 LL |         x_i32 > x_i8;
-   |                 ^^^^ expected `i32`, found `i8`
+   |         -----   ^^^^ expected `i32`, found `i8`
+   |         |
+   |         expected because this is `i32`
    |
 help: you can convert an `i8` to an `i32`
    |
@@ -453,7 +535,9 @@ error[E0308]: mismatched types
   --> $DIR/numeric-cast-binop.rs:116:17
    |
 LL |         x_i32 > x_i16;
-   |                 ^^^^^ expected `i32`, found `i16`
+   |         -----   ^^^^^ expected `i32`, found `i16`
+   |         |
+   |         expected because this is `i32`
    |
 help: you can convert an `i16` to an `i32`
    |
@@ -464,7 +548,9 @@ error[E0308]: mismatched types
   --> $DIR/numeric-cast-binop.rs:118:17
    |
 LL |         x_i32 > x_i64;
-   |                 ^^^^^ expected `i32`, found `i64`
+   |         -----   ^^^^^ expected `i32`, found `i64`
+   |         |
+   |         expected because this is `i32`
    |
 help: you can convert `x_i32` from `i32` to `i64`, matching the type of `x_i64`
    |
@@ -475,7 +561,9 @@ error[E0308]: mismatched types
   --> $DIR/numeric-cast-binop.rs:120:17
    |
 LL |         x_i32 > x_i128;
-   |                 ^^^^^^ expected `i32`, found `i128`
+   |         -----   ^^^^^^ expected `i32`, found `i128`
+   |         |
+   |         expected because this is `i32`
    |
 help: you can convert `x_i32` from `i32` to `i128`, matching the type of `x_i128`
    |
@@ -486,7 +574,9 @@ error[E0308]: mismatched types
   --> $DIR/numeric-cast-binop.rs:122:17
    |
 LL |         x_i32 > x_isize;
-   |                 ^^^^^^^ expected `i32`, found `isize`
+   |         -----   ^^^^^^^ expected `i32`, found `isize`
+   |         |
+   |         expected because this is `i32`
    |
 help: you can convert an `isize` to an `i32` and panic if the converted value doesn't fit
    |
@@ -497,7 +587,9 @@ error[E0308]: mismatched types
   --> $DIR/numeric-cast-binop.rs:125:17
    |
 LL |         x_i64 > x_i8;
-   |                 ^^^^ expected `i64`, found `i8`
+   |         -----   ^^^^ expected `i64`, found `i8`
+   |         |
+   |         expected because this is `i64`
    |
 help: you can convert an `i8` to an `i64`
    |
@@ -508,7 +600,9 @@ error[E0308]: mismatched types
   --> $DIR/numeric-cast-binop.rs:127:17
    |
 LL |         x_i64 > x_i16;
-   |                 ^^^^^ expected `i64`, found `i16`
+   |         -----   ^^^^^ expected `i64`, found `i16`
+   |         |
+   |         expected because this is `i64`
    |
 help: you can convert an `i16` to an `i64`
    |
@@ -519,7 +613,9 @@ error[E0308]: mismatched types
   --> $DIR/numeric-cast-binop.rs:129:17
    |
 LL |         x_i64 > x_i32;
-   |                 ^^^^^ expected `i64`, found `i32`
+   |         -----   ^^^^^ expected `i64`, found `i32`
+   |         |
+   |         expected because this is `i64`
    |
 help: you can convert an `i32` to an `i64`
    |
@@ -530,7 +626,9 @@ error[E0308]: mismatched types
   --> $DIR/numeric-cast-binop.rs:131:17
    |
 LL |         x_i64 > x_i128;
-   |                 ^^^^^^ expected `i64`, found `i128`
+   |         -----   ^^^^^^ expected `i64`, found `i128`
+   |         |
+   |         expected because this is `i64`
    |
 help: you can convert `x_i64` from `i64` to `i128`, matching the type of `x_i128`
    |
@@ -541,7 +639,9 @@ error[E0308]: mismatched types
   --> $DIR/numeric-cast-binop.rs:133:17
    |
 LL |         x_i64 > x_isize;
-   |                 ^^^^^^^ expected `i64`, found `isize`
+   |         -----   ^^^^^^^ expected `i64`, found `isize`
+   |         |
+   |         expected because this is `i64`
    |
 help: you can convert an `isize` to an `i64` and panic if the converted value doesn't fit
    |
@@ -552,7 +652,9 @@ error[E0308]: mismatched types
   --> $DIR/numeric-cast-binop.rs:136:18
    |
 LL |         x_i128 > x_i8;
-   |                  ^^^^ expected `i128`, found `i8`
+   |         ------   ^^^^ expected `i128`, found `i8`
+   |         |
+   |         expected because this is `i128`
    |
 help: you can convert an `i8` to an `i128`
    |
@@ -563,7 +665,9 @@ error[E0308]: mismatched types
   --> $DIR/numeric-cast-binop.rs:138:18
    |
 LL |         x_i128 > x_i16;
-   |                  ^^^^^ expected `i128`, found `i16`
+   |         ------   ^^^^^ expected `i128`, found `i16`
+   |         |
+   |         expected because this is `i128`
    |
 help: you can convert an `i16` to an `i128`
    |
@@ -574,7 +678,9 @@ error[E0308]: mismatched types
   --> $DIR/numeric-cast-binop.rs:140:18
    |
 LL |         x_i128 > x_i32;
-   |                  ^^^^^ expected `i128`, found `i32`
+   |         ------   ^^^^^ expected `i128`, found `i32`
+   |         |
+   |         expected because this is `i128`
    |
 help: you can convert an `i32` to an `i128`
    |
@@ -585,7 +691,9 @@ error[E0308]: mismatched types
   --> $DIR/numeric-cast-binop.rs:142:18
    |
 LL |         x_i128 > x_i64;
-   |                  ^^^^^ expected `i128`, found `i64`
+   |         ------   ^^^^^ expected `i128`, found `i64`
+   |         |
+   |         expected because this is `i128`
    |
 help: you can convert an `i64` to an `i128`
    |
@@ -596,7 +704,9 @@ error[E0308]: mismatched types
   --> $DIR/numeric-cast-binop.rs:144:18
    |
 LL |         x_i128 > x_isize;
-   |                  ^^^^^^^ expected `i128`, found `isize`
+   |         ------   ^^^^^^^ expected `i128`, found `isize`
+   |         |
+   |         expected because this is `i128`
    |
 help: you can convert an `isize` to an `i128` and panic if the converted value doesn't fit
    |
@@ -607,7 +717,9 @@ error[E0308]: mismatched types
   --> $DIR/numeric-cast-binop.rs:147:19
    |
 LL |         x_isize > x_i8;
-   |                   ^^^^ expected `isize`, found `i8`
+   |         -------   ^^^^ expected `isize`, found `i8`
+   |         |
+   |         expected because this is `isize`
    |
 help: you can convert an `i8` to an `isize`
    |
@@ -618,7 +730,9 @@ error[E0308]: mismatched types
   --> $DIR/numeric-cast-binop.rs:149:19
    |
 LL |         x_isize > x_i16;
-   |                   ^^^^^ expected `isize`, found `i16`
+   |         -------   ^^^^^ expected `isize`, found `i16`
+   |         |
+   |         expected because this is `isize`
    |
 help: you can convert an `i16` to an `isize`
    |
@@ -629,7 +743,9 @@ error[E0308]: mismatched types
   --> $DIR/numeric-cast-binop.rs:151:19
    |
 LL |         x_isize > x_i32;
-   |                   ^^^^^ expected `isize`, found `i32`
+   |         -------   ^^^^^ expected `isize`, found `i32`
+   |         |
+   |         expected because this is `isize`
    |
 help: you can convert an `i32` to an `isize` and panic if the converted value doesn't fit
    |
@@ -640,7 +756,9 @@ error[E0308]: mismatched types
   --> $DIR/numeric-cast-binop.rs:153:19
    |
 LL |         x_isize > x_i64;
-   |                   ^^^^^ expected `isize`, found `i64`
+   |         -------   ^^^^^ expected `isize`, found `i64`
+   |         |
+   |         expected because this is `isize`
    |
 help: you can convert an `i64` to an `isize` and panic if the converted value doesn't fit
    |
@@ -651,7 +769,9 @@ error[E0308]: mismatched types
   --> $DIR/numeric-cast-binop.rs:155:19
    |
 LL |         x_isize > x_i128;
-   |                   ^^^^^^ expected `isize`, found `i128`
+   |         -------   ^^^^^^ expected `isize`, found `i128`
+   |         |
+   |         expected because this is `isize`
    |
 help: you can convert an `i128` to an `isize` and panic if the converted value doesn't fit
    |
@@ -662,7 +782,9 @@ error[E0308]: mismatched types
   --> $DIR/numeric-cast-binop.rs:161:16
    |
 LL |         x_u8 > x_i8;
-   |                ^^^^ expected `u8`, found `i8`
+   |         ----   ^^^^ expected `u8`, found `i8`
+   |         |
+   |         expected because this is `u8`
    |
 help: you can convert an `i8` to a `u8` and panic if the converted value doesn't fit
    |
@@ -673,7 +795,9 @@ error[E0308]: mismatched types
   --> $DIR/numeric-cast-binop.rs:163:16
    |
 LL |         x_u8 > x_i16;
-   |                ^^^^^ expected `u8`, found `i16`
+   |         ----   ^^^^^ expected `u8`, found `i16`
+   |         |
+   |         expected because this is `u8`
    |
 help: you can convert `x_u8` from `u8` to `i16`, matching the type of `x_i16`
    |
@@ -684,7 +808,9 @@ error[E0308]: mismatched types
   --> $DIR/numeric-cast-binop.rs:165:16
    |
 LL |         x_u8 > x_i32;
-   |                ^^^^^ expected `u8`, found `i32`
+   |         ----   ^^^^^ expected `u8`, found `i32`
+   |         |
+   |         expected because this is `u8`
    |
 help: you can convert `x_u8` from `u8` to `i32`, matching the type of `x_i32`
    |
@@ -695,7 +821,9 @@ error[E0308]: mismatched types
   --> $DIR/numeric-cast-binop.rs:167:16
    |
 LL |         x_u8 > x_i64;
-   |                ^^^^^ expected `u8`, found `i64`
+   |         ----   ^^^^^ expected `u8`, found `i64`
+   |         |
+   |         expected because this is `u8`
    |
 help: you can convert `x_u8` from `u8` to `i64`, matching the type of `x_i64`
    |
@@ -706,7 +834,9 @@ error[E0308]: mismatched types
   --> $DIR/numeric-cast-binop.rs:169:16
    |
 LL |         x_u8 > x_i128;
-   |                ^^^^^^ expected `u8`, found `i128`
+   |         ----   ^^^^^^ expected `u8`, found `i128`
+   |         |
+   |         expected because this is `u8`
    |
 help: you can convert `x_u8` from `u8` to `i128`, matching the type of `x_i128`
    |
@@ -717,7 +847,9 @@ error[E0308]: mismatched types
   --> $DIR/numeric-cast-binop.rs:171:16
    |
 LL |         x_u8 > x_isize;
-   |                ^^^^^^^ expected `u8`, found `isize`
+   |         ----   ^^^^^^^ expected `u8`, found `isize`
+   |         |
+   |         expected because this is `u8`
    |
 help: you can convert `x_u8` from `u8` to `isize`, matching the type of `x_isize`
    |
@@ -728,7 +860,9 @@ error[E0308]: mismatched types
   --> $DIR/numeric-cast-binop.rs:174:17
    |
 LL |         x_u16 > x_i8;
-   |                 ^^^^ expected `u16`, found `i8`
+   |         -----   ^^^^ expected `u16`, found `i8`
+   |         |
+   |         expected because this is `u16`
    |
 help: you can convert an `i8` to a `u16` and panic if the converted value doesn't fit
    |
@@ -739,7 +873,9 @@ error[E0308]: mismatched types
   --> $DIR/numeric-cast-binop.rs:176:17
    |
 LL |         x_u16 > x_i16;
-   |                 ^^^^^ expected `u16`, found `i16`
+   |         -----   ^^^^^ expected `u16`, found `i16`
+   |         |
+   |         expected because this is `u16`
    |
 help: you can convert an `i16` to a `u16` and panic if the converted value doesn't fit
    |
@@ -750,7 +886,9 @@ error[E0308]: mismatched types
   --> $DIR/numeric-cast-binop.rs:178:17
    |
 LL |         x_u16 > x_i32;
-   |                 ^^^^^ expected `u16`, found `i32`
+   |         -----   ^^^^^ expected `u16`, found `i32`
+   |         |
+   |         expected because this is `u16`
    |
 help: you can convert `x_u16` from `u16` to `i32`, matching the type of `x_i32`
    |
@@ -761,7 +899,9 @@ error[E0308]: mismatched types
   --> $DIR/numeric-cast-binop.rs:180:17
    |
 LL |         x_u16 > x_i64;
-   |                 ^^^^^ expected `u16`, found `i64`
+   |         -----   ^^^^^ expected `u16`, found `i64`
+   |         |
+   |         expected because this is `u16`
    |
 help: you can convert `x_u16` from `u16` to `i64`, matching the type of `x_i64`
    |
@@ -772,7 +912,9 @@ error[E0308]: mismatched types
   --> $DIR/numeric-cast-binop.rs:182:17
    |
 LL |         x_u16 > x_i128;
-   |                 ^^^^^^ expected `u16`, found `i128`
+   |         -----   ^^^^^^ expected `u16`, found `i128`
+   |         |
+   |         expected because this is `u16`
    |
 help: you can convert `x_u16` from `u16` to `i128`, matching the type of `x_i128`
    |
@@ -783,7 +925,9 @@ error[E0308]: mismatched types
   --> $DIR/numeric-cast-binop.rs:184:17
    |
 LL |         x_u16 > x_isize;
-   |                 ^^^^^^^ expected `u16`, found `isize`
+   |         -----   ^^^^^^^ expected `u16`, found `isize`
+   |         |
+   |         expected because this is `u16`
    |
 help: you can convert an `isize` to a `u16` and panic if the converted value doesn't fit
    |
@@ -794,7 +938,9 @@ error[E0308]: mismatched types
   --> $DIR/numeric-cast-binop.rs:187:17
    |
 LL |         x_u32 > x_i8;
-   |                 ^^^^ expected `u32`, found `i8`
+   |         -----   ^^^^ expected `u32`, found `i8`
+   |         |
+   |         expected because this is `u32`
    |
 help: you can convert an `i8` to a `u32` and panic if the converted value doesn't fit
    |
@@ -805,7 +951,9 @@ error[E0308]: mismatched types
   --> $DIR/numeric-cast-binop.rs:189:17
    |
 LL |         x_u32 > x_i16;
-   |                 ^^^^^ expected `u32`, found `i16`
+   |         -----   ^^^^^ expected `u32`, found `i16`
+   |         |
+   |         expected because this is `u32`
    |
 help: you can convert an `i16` to a `u32` and panic if the converted value doesn't fit
    |
@@ -816,7 +964,9 @@ error[E0308]: mismatched types
   --> $DIR/numeric-cast-binop.rs:191:17
    |
 LL |         x_u32 > x_i32;
-   |                 ^^^^^ expected `u32`, found `i32`
+   |         -----   ^^^^^ expected `u32`, found `i32`
+   |         |
+   |         expected because this is `u32`
    |
 help: you can convert an `i32` to a `u32` and panic if the converted value doesn't fit
    |
@@ -827,7 +977,9 @@ error[E0308]: mismatched types
   --> $DIR/numeric-cast-binop.rs:193:17
    |
 LL |         x_u32 > x_i64;
-   |                 ^^^^^ expected `u32`, found `i64`
+   |         -----   ^^^^^ expected `u32`, found `i64`
+   |         |
+   |         expected because this is `u32`
    |
 help: you can convert `x_u32` from `u32` to `i64`, matching the type of `x_i64`
    |
@@ -838,7 +990,9 @@ error[E0308]: mismatched types
   --> $DIR/numeric-cast-binop.rs:195:17
    |
 LL |         x_u32 > x_i128;
-   |                 ^^^^^^ expected `u32`, found `i128`
+   |         -----   ^^^^^^ expected `u32`, found `i128`
+   |         |
+   |         expected because this is `u32`
    |
 help: you can convert `x_u32` from `u32` to `i128`, matching the type of `x_i128`
    |
@@ -849,7 +1003,9 @@ error[E0308]: mismatched types
   --> $DIR/numeric-cast-binop.rs:197:17
    |
 LL |         x_u32 > x_isize;
-   |                 ^^^^^^^ expected `u32`, found `isize`
+   |         -----   ^^^^^^^ expected `u32`, found `isize`
+   |         |
+   |         expected because this is `u32`
    |
 help: you can convert an `isize` to a `u32` and panic if the converted value doesn't fit
    |
@@ -860,7 +1016,9 @@ error[E0308]: mismatched types
   --> $DIR/numeric-cast-binop.rs:200:17
    |
 LL |         x_u64 > x_i8;
-   |                 ^^^^ expected `u64`, found `i8`
+   |         -----   ^^^^ expected `u64`, found `i8`
+   |         |
+   |         expected because this is `u64`
    |
 help: you can convert an `i8` to a `u64` and panic if the converted value doesn't fit
    |
@@ -871,7 +1029,9 @@ error[E0308]: mismatched types
   --> $DIR/numeric-cast-binop.rs:202:17
    |
 LL |         x_u64 > x_i16;
-   |                 ^^^^^ expected `u64`, found `i16`
+   |         -----   ^^^^^ expected `u64`, found `i16`
+   |         |
+   |         expected because this is `u64`
    |
 help: you can convert an `i16` to a `u64` and panic if the converted value doesn't fit
    |
@@ -882,7 +1042,9 @@ error[E0308]: mismatched types
   --> $DIR/numeric-cast-binop.rs:204:17
    |
 LL |         x_u64 > x_i32;
-   |                 ^^^^^ expected `u64`, found `i32`
+   |         -----   ^^^^^ expected `u64`, found `i32`
+   |         |
+   |         expected because this is `u64`
    |
 help: you can convert an `i32` to a `u64` and panic if the converted value doesn't fit
    |
@@ -893,7 +1055,9 @@ error[E0308]: mismatched types
   --> $DIR/numeric-cast-binop.rs:206:17
    |
 LL |         x_u64 > x_i64;
-   |                 ^^^^^ expected `u64`, found `i64`
+   |         -----   ^^^^^ expected `u64`, found `i64`
+   |         |
+   |         expected because this is `u64`
    |
 help: you can convert an `i64` to a `u64` and panic if the converted value doesn't fit
    |
@@ -904,7 +1068,9 @@ error[E0308]: mismatched types
   --> $DIR/numeric-cast-binop.rs:208:17
    |
 LL |         x_u64 > x_i128;
-   |                 ^^^^^^ expected `u64`, found `i128`
+   |         -----   ^^^^^^ expected `u64`, found `i128`
+   |         |
+   |         expected because this is `u64`
    |
 help: you can convert `x_u64` from `u64` to `i128`, matching the type of `x_i128`
    |
@@ -915,7 +1081,9 @@ error[E0308]: mismatched types
   --> $DIR/numeric-cast-binop.rs:210:17
    |
 LL |         x_u64 > x_isize;
-   |                 ^^^^^^^ expected `u64`, found `isize`
+   |         -----   ^^^^^^^ expected `u64`, found `isize`
+   |         |
+   |         expected because this is `u64`
    |
 help: you can convert an `isize` to a `u64` and panic if the converted value doesn't fit
    |
@@ -926,7 +1094,9 @@ error[E0308]: mismatched types
   --> $DIR/numeric-cast-binop.rs:213:18
    |
 LL |         x_u128 > x_i8;
-   |                  ^^^^ expected `u128`, found `i8`
+   |         ------   ^^^^ expected `u128`, found `i8`
+   |         |
+   |         expected because this is `u128`
    |
 help: you can convert an `i8` to a `u128` and panic if the converted value doesn't fit
    |
@@ -937,7 +1107,9 @@ error[E0308]: mismatched types
   --> $DIR/numeric-cast-binop.rs:215:18
    |
 LL |         x_u128 > x_i16;
-   |                  ^^^^^ expected `u128`, found `i16`
+   |         ------   ^^^^^ expected `u128`, found `i16`
+   |         |
+   |         expected because this is `u128`
    |
 help: you can convert an `i16` to a `u128` and panic if the converted value doesn't fit
    |
@@ -948,7 +1120,9 @@ error[E0308]: mismatched types
   --> $DIR/numeric-cast-binop.rs:217:18
    |
 LL |         x_u128 > x_i32;
-   |                  ^^^^^ expected `u128`, found `i32`
+   |         ------   ^^^^^ expected `u128`, found `i32`
+   |         |
+   |         expected because this is `u128`
    |
 help: you can convert an `i32` to a `u128` and panic if the converted value doesn't fit
    |
@@ -959,7 +1133,9 @@ error[E0308]: mismatched types
   --> $DIR/numeric-cast-binop.rs:219:18
    |
 LL |         x_u128 > x_i64;
-   |                  ^^^^^ expected `u128`, found `i64`
+   |         ------   ^^^^^ expected `u128`, found `i64`
+   |         |
+   |         expected because this is `u128`
    |
 help: you can convert an `i64` to a `u128` and panic if the converted value doesn't fit
    |
@@ -970,7 +1146,9 @@ error[E0308]: mismatched types
   --> $DIR/numeric-cast-binop.rs:221:18
    |
 LL |         x_u128 > x_i128;
-   |                  ^^^^^^ expected `u128`, found `i128`
+   |         ------   ^^^^^^ expected `u128`, found `i128`
+   |         |
+   |         expected because this is `u128`
    |
 help: you can convert an `i128` to a `u128` and panic if the converted value doesn't fit
    |
@@ -981,7 +1159,9 @@ error[E0308]: mismatched types
   --> $DIR/numeric-cast-binop.rs:223:18
    |
 LL |         x_u128 > x_isize;
-   |                  ^^^^^^^ expected `u128`, found `isize`
+   |         ------   ^^^^^^^ expected `u128`, found `isize`
+   |         |
+   |         expected because this is `u128`
    |
 help: you can convert an `isize` to a `u128` and panic if the converted value doesn't fit
    |
@@ -992,7 +1172,9 @@ error[E0308]: mismatched types
   --> $DIR/numeric-cast-binop.rs:226:19
    |
 LL |         x_usize > x_i8;
-   |                   ^^^^ expected `usize`, found `i8`
+   |         -------   ^^^^ expected `usize`, found `i8`
+   |         |
+   |         expected because this is `usize`
    |
 help: you can convert an `i8` to a `usize` and panic if the converted value doesn't fit
    |
@@ -1003,7 +1185,9 @@ error[E0308]: mismatched types
   --> $DIR/numeric-cast-binop.rs:228:19
    |
 LL |         x_usize > x_i16;
-   |                   ^^^^^ expected `usize`, found `i16`
+   |         -------   ^^^^^ expected `usize`, found `i16`
+   |         |
+   |         expected because this is `usize`
    |
 help: you can convert an `i16` to a `usize` and panic if the converted value doesn't fit
    |
@@ -1014,7 +1198,9 @@ error[E0308]: mismatched types
   --> $DIR/numeric-cast-binop.rs:230:19
    |
 LL |         x_usize > x_i32;
-   |                   ^^^^^ expected `usize`, found `i32`
+   |         -------   ^^^^^ expected `usize`, found `i32`
+   |         |
+   |         expected because this is `usize`
    |
 help: you can convert an `i32` to a `usize` and panic if the converted value doesn't fit
    |
@@ -1025,7 +1211,9 @@ error[E0308]: mismatched types
   --> $DIR/numeric-cast-binop.rs:232:19
    |
 LL |         x_usize > x_i64;
-   |                   ^^^^^ expected `usize`, found `i64`
+   |         -------   ^^^^^ expected `usize`, found `i64`
+   |         |
+   |         expected because this is `usize`
    |
 help: you can convert an `i64` to a `usize` and panic if the converted value doesn't fit
    |
@@ -1036,7 +1224,9 @@ error[E0308]: mismatched types
   --> $DIR/numeric-cast-binop.rs:234:19
    |
 LL |         x_usize > x_i128;
-   |                   ^^^^^^ expected `usize`, found `i128`
+   |         -------   ^^^^^^ expected `usize`, found `i128`
+   |         |
+   |         expected because this is `usize`
    |
 help: you can convert an `i128` to a `usize` and panic if the converted value doesn't fit
    |
@@ -1047,7 +1237,9 @@ error[E0308]: mismatched types
   --> $DIR/numeric-cast-binop.rs:236:19
    |
 LL |         x_usize > x_isize;
-   |                   ^^^^^^^ expected `usize`, found `isize`
+   |         -------   ^^^^^^^ expected `usize`, found `isize`
+   |         |
+   |         expected because this is `usize`
    |
 help: you can convert an `isize` to a `usize` and panic if the converted value doesn't fit
    |
@@ -1058,7 +1250,9 @@ error[E0308]: mismatched types
   --> $DIR/numeric-cast-binop.rs:242:16
    |
 LL |         x_i8 > x_u8;
-   |                ^^^^ expected `i8`, found `u8`
+   |         ----   ^^^^ expected `i8`, found `u8`
+   |         |
+   |         expected because this is `i8`
    |
 help: you can convert a `u8` to an `i8` and panic if the converted value doesn't fit
    |
@@ -1069,7 +1263,9 @@ error[E0308]: mismatched types
   --> $DIR/numeric-cast-binop.rs:244:16
    |
 LL |         x_i8 > x_u16;
-   |                ^^^^^ expected `i8`, found `u16`
+   |         ----   ^^^^^ expected `i8`, found `u16`
+   |         |
+   |         expected because this is `i8`
    |
 help: you can convert a `u16` to an `i8` and panic if the converted value doesn't fit
    |
@@ -1080,7 +1276,9 @@ error[E0308]: mismatched types
   --> $DIR/numeric-cast-binop.rs:246:16
    |
 LL |         x_i8 > x_u32;
-   |                ^^^^^ expected `i8`, found `u32`
+   |         ----   ^^^^^ expected `i8`, found `u32`
+   |         |
+   |         expected because this is `i8`
    |
 help: you can convert a `u32` to an `i8` and panic if the converted value doesn't fit
    |
@@ -1091,7 +1289,9 @@ error[E0308]: mismatched types
   --> $DIR/numeric-cast-binop.rs:248:16
    |
 LL |         x_i8 > x_u64;
-   |                ^^^^^ expected `i8`, found `u64`
+   |         ----   ^^^^^ expected `i8`, found `u64`
+   |         |
+   |         expected because this is `i8`
    |
 help: you can convert a `u64` to an `i8` and panic if the converted value doesn't fit
    |
@@ -1102,7 +1302,9 @@ error[E0308]: mismatched types
   --> $DIR/numeric-cast-binop.rs:250:16
    |
 LL |         x_i8 > x_u128;
-   |                ^^^^^^ expected `i8`, found `u128`
+   |         ----   ^^^^^^ expected `i8`, found `u128`
+   |         |
+   |         expected because this is `i8`
    |
 help: you can convert a `u128` to an `i8` and panic if the converted value doesn't fit
    |
@@ -1113,7 +1315,9 @@ error[E0308]: mismatched types
   --> $DIR/numeric-cast-binop.rs:252:16
    |
 LL |         x_i8 > x_usize;
-   |                ^^^^^^^ expected `i8`, found `usize`
+   |         ----   ^^^^^^^ expected `i8`, found `usize`
+   |         |
+   |         expected because this is `i8`
    |
 help: you can convert a `usize` to an `i8` and panic if the converted value doesn't fit
    |
@@ -1124,7 +1328,9 @@ error[E0308]: mismatched types
   --> $DIR/numeric-cast-binop.rs:255:17
    |
 LL |         x_i16 > x_u8;
-   |                 ^^^^ expected `i16`, found `u8`
+   |         -----   ^^^^ expected `i16`, found `u8`
+   |         |
+   |         expected because this is `i16`
    |
 help: you can convert a `u8` to an `i16`
    |
@@ -1135,7 +1341,9 @@ error[E0308]: mismatched types
   --> $DIR/numeric-cast-binop.rs:257:17
    |
 LL |         x_i16 > x_u16;
-   |                 ^^^^^ expected `i16`, found `u16`
+   |         -----   ^^^^^ expected `i16`, found `u16`
+   |         |
+   |         expected because this is `i16`
    |
 help: you can convert a `u16` to an `i16` and panic if the converted value doesn't fit
    |
@@ -1146,7 +1354,9 @@ error[E0308]: mismatched types
   --> $DIR/numeric-cast-binop.rs:259:17
    |
 LL |         x_i16 > x_u32;
-   |                 ^^^^^ expected `i16`, found `u32`
+   |         -----   ^^^^^ expected `i16`, found `u32`
+   |         |
+   |         expected because this is `i16`
    |
 help: you can convert a `u32` to an `i16` and panic if the converted value doesn't fit
    |
@@ -1157,7 +1367,9 @@ error[E0308]: mismatched types
   --> $DIR/numeric-cast-binop.rs:261:17
    |
 LL |         x_i16 > x_u64;
-   |                 ^^^^^ expected `i16`, found `u64`
+   |         -----   ^^^^^ expected `i16`, found `u64`
+   |         |
+   |         expected because this is `i16`
    |
 help: you can convert a `u64` to an `i16` and panic if the converted value doesn't fit
    |
@@ -1168,7 +1380,9 @@ error[E0308]: mismatched types
   --> $DIR/numeric-cast-binop.rs:263:17
    |
 LL |         x_i16 > x_u128;
-   |                 ^^^^^^ expected `i16`, found `u128`
+   |         -----   ^^^^^^ expected `i16`, found `u128`
+   |         |
+   |         expected because this is `i16`
    |
 help: you can convert a `u128` to an `i16` and panic if the converted value doesn't fit
    |
@@ -1179,7 +1393,9 @@ error[E0308]: mismatched types
   --> $DIR/numeric-cast-binop.rs:265:17
    |
 LL |         x_i16 > x_usize;
-   |                 ^^^^^^^ expected `i16`, found `usize`
+   |         -----   ^^^^^^^ expected `i16`, found `usize`
+   |         |
+   |         expected because this is `i16`
    |
 help: you can convert a `usize` to an `i16` and panic if the converted value doesn't fit
    |
@@ -1190,7 +1406,9 @@ error[E0308]: mismatched types
   --> $DIR/numeric-cast-binop.rs:268:17
    |
 LL |         x_i32 > x_u8;
-   |                 ^^^^ expected `i32`, found `u8`
+   |         -----   ^^^^ expected `i32`, found `u8`
+   |         |
+   |         expected because this is `i32`
    |
 help: you can convert a `u8` to an `i32`
    |
@@ -1201,7 +1419,9 @@ error[E0308]: mismatched types
   --> $DIR/numeric-cast-binop.rs:270:17
    |
 LL |         x_i32 > x_u16;
-   |                 ^^^^^ expected `i32`, found `u16`
+   |         -----   ^^^^^ expected `i32`, found `u16`
+   |         |
+   |         expected because this is `i32`
    |
 help: you can convert a `u16` to an `i32`
    |
@@ -1212,7 +1432,9 @@ error[E0308]: mismatched types
   --> $DIR/numeric-cast-binop.rs:272:17
    |
 LL |         x_i32 > x_u32;
-   |                 ^^^^^ expected `i32`, found `u32`
+   |         -----   ^^^^^ expected `i32`, found `u32`
+   |         |
+   |         expected because this is `i32`
    |
 help: you can convert a `u32` to an `i32` and panic if the converted value doesn't fit
    |
@@ -1223,7 +1445,9 @@ error[E0308]: mismatched types
   --> $DIR/numeric-cast-binop.rs:274:17
    |
 LL |         x_i32 > x_u64;
-   |                 ^^^^^ expected `i32`, found `u64`
+   |         -----   ^^^^^ expected `i32`, found `u64`
+   |         |
+   |         expected because this is `i32`
    |
 help: you can convert a `u64` to an `i32` and panic if the converted value doesn't fit
    |
@@ -1234,7 +1458,9 @@ error[E0308]: mismatched types
   --> $DIR/numeric-cast-binop.rs:276:17
    |
 LL |         x_i32 > x_u128;
-   |                 ^^^^^^ expected `i32`, found `u128`
+   |         -----   ^^^^^^ expected `i32`, found `u128`
+   |         |
+   |         expected because this is `i32`
    |
 help: you can convert a `u128` to an `i32` and panic if the converted value doesn't fit
    |
@@ -1245,7 +1471,9 @@ error[E0308]: mismatched types
   --> $DIR/numeric-cast-binop.rs:278:17
    |
 LL |         x_i32 > x_usize;
-   |                 ^^^^^^^ expected `i32`, found `usize`
+   |         -----   ^^^^^^^ expected `i32`, found `usize`
+   |         |
+   |         expected because this is `i32`
    |
 help: you can convert a `usize` to an `i32` and panic if the converted value doesn't fit
    |
@@ -1256,7 +1484,9 @@ error[E0308]: mismatched types
   --> $DIR/numeric-cast-binop.rs:281:17
    |
 LL |         x_i64 > x_u8;
-   |                 ^^^^ expected `i64`, found `u8`
+   |         -----   ^^^^ expected `i64`, found `u8`
+   |         |
+   |         expected because this is `i64`
    |
 help: you can convert a `u8` to an `i64`
    |
@@ -1267,7 +1497,9 @@ error[E0308]: mismatched types
   --> $DIR/numeric-cast-binop.rs:283:17
    |
 LL |         x_i64 > x_u16;
-   |                 ^^^^^ expected `i64`, found `u16`
+   |         -----   ^^^^^ expected `i64`, found `u16`
+   |         |
+   |         expected because this is `i64`
    |
 help: you can convert a `u16` to an `i64`
    |
@@ -1278,7 +1510,9 @@ error[E0308]: mismatched types
   --> $DIR/numeric-cast-binop.rs:285:17
    |
 LL |         x_i64 > x_u32;
-   |                 ^^^^^ expected `i64`, found `u32`
+   |         -----   ^^^^^ expected `i64`, found `u32`
+   |         |
+   |         expected because this is `i64`
    |
 help: you can convert a `u32` to an `i64`
    |
@@ -1289,7 +1523,9 @@ error[E0308]: mismatched types
   --> $DIR/numeric-cast-binop.rs:287:17
    |
 LL |         x_i64 > x_u64;
-   |                 ^^^^^ expected `i64`, found `u64`
+   |         -----   ^^^^^ expected `i64`, found `u64`
+   |         |
+   |         expected because this is `i64`
    |
 help: you can convert a `u64` to an `i64` and panic if the converted value doesn't fit
    |
@@ -1300,7 +1536,9 @@ error[E0308]: mismatched types
   --> $DIR/numeric-cast-binop.rs:289:17
    |
 LL |         x_i64 > x_u128;
-   |                 ^^^^^^ expected `i64`, found `u128`
+   |         -----   ^^^^^^ expected `i64`, found `u128`
+   |         |
+   |         expected because this is `i64`
    |
 help: you can convert a `u128` to an `i64` and panic if the converted value doesn't fit
    |
@@ -1311,7 +1549,9 @@ error[E0308]: mismatched types
   --> $DIR/numeric-cast-binop.rs:291:17
    |
 LL |         x_i64 > x_usize;
-   |                 ^^^^^^^ expected `i64`, found `usize`
+   |         -----   ^^^^^^^ expected `i64`, found `usize`
+   |         |
+   |         expected because this is `i64`
    |
 help: you can convert a `usize` to an `i64` and panic if the converted value doesn't fit
    |
@@ -1322,7 +1562,9 @@ error[E0308]: mismatched types
   --> $DIR/numeric-cast-binop.rs:294:18
    |
 LL |         x_i128 > x_u8;
-   |                  ^^^^ expected `i128`, found `u8`
+   |         ------   ^^^^ expected `i128`, found `u8`
+   |         |
+   |         expected because this is `i128`
    |
 help: you can convert a `u8` to an `i128`
    |
@@ -1333,7 +1575,9 @@ error[E0308]: mismatched types
   --> $DIR/numeric-cast-binop.rs:296:18
    |
 LL |         x_i128 > x_u16;
-   |                  ^^^^^ expected `i128`, found `u16`
+   |         ------   ^^^^^ expected `i128`, found `u16`
+   |         |
+   |         expected because this is `i128`
    |
 help: you can convert a `u16` to an `i128`
    |
@@ -1344,7 +1588,9 @@ error[E0308]: mismatched types
   --> $DIR/numeric-cast-binop.rs:298:18
    |
 LL |         x_i128 > x_u32;
-   |                  ^^^^^ expected `i128`, found `u32`
+   |         ------   ^^^^^ expected `i128`, found `u32`
+   |         |
+   |         expected because this is `i128`
    |
 help: you can convert a `u32` to an `i128`
    |
@@ -1355,7 +1601,9 @@ error[E0308]: mismatched types
   --> $DIR/numeric-cast-binop.rs:300:18
    |
 LL |         x_i128 > x_u64;
-   |                  ^^^^^ expected `i128`, found `u64`
+   |         ------   ^^^^^ expected `i128`, found `u64`
+   |         |
+   |         expected because this is `i128`
    |
 help: you can convert a `u64` to an `i128`
    |
@@ -1366,7 +1614,9 @@ error[E0308]: mismatched types
   --> $DIR/numeric-cast-binop.rs:302:18
    |
 LL |         x_i128 > x_u128;
-   |                  ^^^^^^ expected `i128`, found `u128`
+   |         ------   ^^^^^^ expected `i128`, found `u128`
+   |         |
+   |         expected because this is `i128`
    |
 help: you can convert a `u128` to an `i128` and panic if the converted value doesn't fit
    |
@@ -1377,7 +1627,9 @@ error[E0308]: mismatched types
   --> $DIR/numeric-cast-binop.rs:304:18
    |
 LL |         x_i128 > x_usize;
-   |                  ^^^^^^^ expected `i128`, found `usize`
+   |         ------   ^^^^^^^ expected `i128`, found `usize`
+   |         |
+   |         expected because this is `i128`
    |
 help: you can convert a `usize` to an `i128` and panic if the converted value doesn't fit
    |
@@ -1388,7 +1640,9 @@ error[E0308]: mismatched types
   --> $DIR/numeric-cast-binop.rs:307:19
    |
 LL |         x_isize > x_u8;
-   |                   ^^^^ expected `isize`, found `u8`
+   |         -------   ^^^^ expected `isize`, found `u8`
+   |         |
+   |         expected because this is `isize`
    |
 help: you can convert a `u8` to an `isize`
    |
@@ -1399,7 +1653,9 @@ error[E0308]: mismatched types
   --> $DIR/numeric-cast-binop.rs:309:19
    |
 LL |         x_isize > x_u16;
-   |                   ^^^^^ expected `isize`, found `u16`
+   |         -------   ^^^^^ expected `isize`, found `u16`
+   |         |
+   |         expected because this is `isize`
    |
 help: you can convert a `u16` to an `isize` and panic if the converted value doesn't fit
    |
@@ -1410,7 +1666,9 @@ error[E0308]: mismatched types
   --> $DIR/numeric-cast-binop.rs:311:19
    |
 LL |         x_isize > x_u32;
-   |                   ^^^^^ expected `isize`, found `u32`
+   |         -------   ^^^^^ expected `isize`, found `u32`
+   |         |
+   |         expected because this is `isize`
    |
 help: you can convert a `u32` to an `isize` and panic if the converted value doesn't fit
    |
@@ -1421,7 +1679,9 @@ error[E0308]: mismatched types
   --> $DIR/numeric-cast-binop.rs:313:19
    |
 LL |         x_isize > x_u64;
-   |                   ^^^^^ expected `isize`, found `u64`
+   |         -------   ^^^^^ expected `isize`, found `u64`
+   |         |
+   |         expected because this is `isize`
    |
 help: you can convert a `u64` to an `isize` and panic if the converted value doesn't fit
    |
@@ -1432,7 +1692,9 @@ error[E0308]: mismatched types
   --> $DIR/numeric-cast-binop.rs:315:19
    |
 LL |         x_isize > x_u128;
-   |                   ^^^^^^ expected `isize`, found `u128`
+   |         -------   ^^^^^^ expected `isize`, found `u128`
+   |         |
+   |         expected because this is `isize`
    |
 help: you can convert a `u128` to an `isize` and panic if the converted value doesn't fit
    |
@@ -1443,7 +1705,9 @@ error[E0308]: mismatched types
   --> $DIR/numeric-cast-binop.rs:317:19
    |
 LL |         x_isize > x_usize;
-   |                   ^^^^^^^ expected `isize`, found `usize`
+   |         -------   ^^^^^^^ expected `isize`, found `usize`
+   |         |
+   |         expected because this is `isize`
    |
 help: you can convert a `usize` to an `isize` and panic if the converted value doesn't fit
    |
index e4843206de1dd48c2025a796c22552b2f612a79a..c244e479d24c6b00493db40c33639faf29f2a137 100644 (file)
@@ -2,7 +2,9 @@ error[E0308]: mismatched types
   --> $DIR/numeric-cast-no-fix.rs:10:15
    |
 LL |     x_usize > -1_isize;
-   |               ^^^^^^^^ expected `usize`, found `isize`
+   |     -------   ^^^^^^^^ expected `usize`, found `isize`
+   |     |
+   |     expected because this is `usize`
    |
    = note: `-1_isize` cannot fit into type `usize`
 
@@ -10,7 +12,9 @@ error[E0308]: mismatched types
   --> $DIR/numeric-cast-no-fix.rs:12:14
    |
 LL |     x_u128 > -1_isize;
-   |              ^^^^^^^^ expected `u128`, found `isize`
+   |     ------   ^^^^^^^^ expected `u128`, found `isize`
+   |     |
+   |     expected because this is `u128`
    |
    = note: `-1_isize` cannot fit into type `u128`
 
@@ -18,7 +22,9 @@ error[E0308]: mismatched types
   --> $DIR/numeric-cast-no-fix.rs:14:13
    |
 LL |     x_u64 > -1_isize;
-   |             ^^^^^^^^ expected `u64`, found `isize`
+   |     -----   ^^^^^^^^ expected `u64`, found `isize`
+   |     |
+   |     expected because this is `u64`
    |
    = note: `-1_isize` cannot fit into type `u64`
 
@@ -26,7 +32,9 @@ error[E0308]: mismatched types
   --> $DIR/numeric-cast-no-fix.rs:16:13
    |
 LL |     x_u32 > -1_isize;
-   |             ^^^^^^^^ expected `u32`, found `isize`
+   |     -----   ^^^^^^^^ expected `u32`, found `isize`
+   |     |
+   |     expected because this is `u32`
    |
    = note: `-1_isize` cannot fit into type `u32`
 
@@ -34,7 +42,9 @@ error[E0308]: mismatched types
   --> $DIR/numeric-cast-no-fix.rs:18:13
    |
 LL |     x_u16 > -1_isize;
-   |             ^^^^^^^^ expected `u16`, found `isize`
+   |     -----   ^^^^^^^^ expected `u16`, found `isize`
+   |     |
+   |     expected because this is `u16`
    |
    = note: `-1_isize` cannot fit into type `u16`
 
@@ -42,7 +52,9 @@ error[E0308]: mismatched types
   --> $DIR/numeric-cast-no-fix.rs:20:12
    |
 LL |     x_u8 > -1_isize;
-   |            ^^^^^^^^ expected `u8`, found `isize`
+   |     ----   ^^^^^^^^ expected `u8`, found `isize`
+   |     |
+   |     expected because this is `u8`
    |
 help: you can convert `x_u8` from `u8` to `isize`, matching the type of `-1_isize`
    |
@@ -53,7 +65,9 @@ error[E0308]: mismatched types
   --> $DIR/numeric-cast-no-fix.rs:23:15
    |
 LL |     x_usize > -1_i128;
-   |               ^^^^^^^ expected `usize`, found `i128`
+   |     -------   ^^^^^^^ expected `usize`, found `i128`
+   |     |
+   |     expected because this is `usize`
    |
    = note: `-1_i128` cannot fit into type `usize`
 
@@ -61,7 +75,9 @@ error[E0308]: mismatched types
   --> $DIR/numeric-cast-no-fix.rs:25:14
    |
 LL |     x_u128 > -1_i128;
-   |              ^^^^^^^ expected `u128`, found `i128`
+   |     ------   ^^^^^^^ expected `u128`, found `i128`
+   |     |
+   |     expected because this is `u128`
    |
    = note: `-1_i128` cannot fit into type `u128`
 
@@ -69,7 +85,9 @@ error[E0308]: mismatched types
   --> $DIR/numeric-cast-no-fix.rs:27:13
    |
 LL |     x_u64 > -1_i128;
-   |             ^^^^^^^ expected `u64`, found `i128`
+   |     -----   ^^^^^^^ expected `u64`, found `i128`
+   |     |
+   |     expected because this is `u64`
    |
 help: you can convert `x_u64` from `u64` to `i128`, matching the type of `-1_i128`
    |
@@ -80,7 +98,9 @@ error[E0308]: mismatched types
   --> $DIR/numeric-cast-no-fix.rs:29:13
    |
 LL |     x_u32 > -1_i128;
-   |             ^^^^^^^ expected `u32`, found `i128`
+   |     -----   ^^^^^^^ expected `u32`, found `i128`
+   |     |
+   |     expected because this is `u32`
    |
 help: you can convert `x_u32` from `u32` to `i128`, matching the type of `-1_i128`
    |
@@ -91,7 +111,9 @@ error[E0308]: mismatched types
   --> $DIR/numeric-cast-no-fix.rs:31:13
    |
 LL |     x_u16 > -1_i128;
-   |             ^^^^^^^ expected `u16`, found `i128`
+   |     -----   ^^^^^^^ expected `u16`, found `i128`
+   |     |
+   |     expected because this is `u16`
    |
 help: you can convert `x_u16` from `u16` to `i128`, matching the type of `-1_i128`
    |
@@ -102,7 +124,9 @@ error[E0308]: mismatched types
   --> $DIR/numeric-cast-no-fix.rs:33:12
    |
 LL |     x_u8 > -1_i128;
-   |            ^^^^^^^ expected `u8`, found `i128`
+   |     ----   ^^^^^^^ expected `u8`, found `i128`
+   |     |
+   |     expected because this is `u8`
    |
 help: you can convert `x_u8` from `u8` to `i128`, matching the type of `-1_i128`
    |
@@ -113,7 +137,9 @@ error[E0308]: mismatched types
   --> $DIR/numeric-cast-no-fix.rs:36:15
    |
 LL |     x_usize > -1_i64;
-   |               ^^^^^^ expected `usize`, found `i64`
+   |     -------   ^^^^^^ expected `usize`, found `i64`
+   |     |
+   |     expected because this is `usize`
    |
    = note: `-1_i64` cannot fit into type `usize`
 
@@ -121,7 +147,9 @@ error[E0308]: mismatched types
   --> $DIR/numeric-cast-no-fix.rs:38:14
    |
 LL |     x_u128 > -1_i64;
-   |              ^^^^^^ expected `u128`, found `i64`
+   |     ------   ^^^^^^ expected `u128`, found `i64`
+   |     |
+   |     expected because this is `u128`
    |
    = note: `-1_i64` cannot fit into type `u128`
 
@@ -129,7 +157,9 @@ error[E0308]: mismatched types
   --> $DIR/numeric-cast-no-fix.rs:40:13
    |
 LL |     x_u64 > -1_i64;
-   |             ^^^^^^ expected `u64`, found `i64`
+   |     -----   ^^^^^^ expected `u64`, found `i64`
+   |     |
+   |     expected because this is `u64`
    |
    = note: `-1_i64` cannot fit into type `u64`
 
@@ -137,7 +167,9 @@ error[E0308]: mismatched types
   --> $DIR/numeric-cast-no-fix.rs:42:13
    |
 LL |     x_u32 > -1_i64;
-   |             ^^^^^^ expected `u32`, found `i64`
+   |     -----   ^^^^^^ expected `u32`, found `i64`
+   |     |
+   |     expected because this is `u32`
    |
 help: you can convert `x_u32` from `u32` to `i64`, matching the type of `-1_i64`
    |
@@ -148,7 +180,9 @@ error[E0308]: mismatched types
   --> $DIR/numeric-cast-no-fix.rs:44:13
    |
 LL |     x_u16 > -1_i64;
-   |             ^^^^^^ expected `u16`, found `i64`
+   |     -----   ^^^^^^ expected `u16`, found `i64`
+   |     |
+   |     expected because this is `u16`
    |
 help: you can convert `x_u16` from `u16` to `i64`, matching the type of `-1_i64`
    |
@@ -159,7 +193,9 @@ error[E0308]: mismatched types
   --> $DIR/numeric-cast-no-fix.rs:46:12
    |
 LL |     x_u8 > -1_i64;
-   |            ^^^^^^ expected `u8`, found `i64`
+   |     ----   ^^^^^^ expected `u8`, found `i64`
+   |     |
+   |     expected because this is `u8`
    |
 help: you can convert `x_u8` from `u8` to `i64`, matching the type of `-1_i64`
    |
@@ -170,7 +206,9 @@ error[E0308]: mismatched types
   --> $DIR/numeric-cast-no-fix.rs:49:15
    |
 LL |     x_usize > -1_i32;
-   |               ^^^^^^ expected `usize`, found `i32`
+   |     -------   ^^^^^^ expected `usize`, found `i32`
+   |     |
+   |     expected because this is `usize`
    |
    = note: `-1_i32` cannot fit into type `usize`
 
@@ -178,7 +216,9 @@ error[E0308]: mismatched types
   --> $DIR/numeric-cast-no-fix.rs:51:14
    |
 LL |     x_u128 > -1_i32;
-   |              ^^^^^^ expected `u128`, found `i32`
+   |     ------   ^^^^^^ expected `u128`, found `i32`
+   |     |
+   |     expected because this is `u128`
    |
    = note: `-1_i32` cannot fit into type `u128`
 
@@ -186,7 +226,9 @@ error[E0308]: mismatched types
   --> $DIR/numeric-cast-no-fix.rs:53:13
    |
 LL |     x_u64 > -1_i32;
-   |             ^^^^^^ expected `u64`, found `i32`
+   |     -----   ^^^^^^ expected `u64`, found `i32`
+   |     |
+   |     expected because this is `u64`
    |
    = note: `-1_i32` cannot fit into type `u64`
 
@@ -194,7 +236,9 @@ error[E0308]: mismatched types
   --> $DIR/numeric-cast-no-fix.rs:55:13
    |
 LL |     x_u32 > -1_i32;
-   |             ^^^^^^ expected `u32`, found `i32`
+   |     -----   ^^^^^^ expected `u32`, found `i32`
+   |     |
+   |     expected because this is `u32`
    |
    = note: `-1_i32` cannot fit into type `u32`
 
@@ -202,7 +246,9 @@ error[E0308]: mismatched types
   --> $DIR/numeric-cast-no-fix.rs:57:13
    |
 LL |     x_u16 > -1_i32;
-   |             ^^^^^^ expected `u16`, found `i32`
+   |     -----   ^^^^^^ expected `u16`, found `i32`
+   |     |
+   |     expected because this is `u16`
    |
 help: you can convert `x_u16` from `u16` to `i32`, matching the type of `-1_i32`
    |
@@ -213,7 +259,9 @@ error[E0308]: mismatched types
   --> $DIR/numeric-cast-no-fix.rs:59:12
    |
 LL |     x_u8 > -1_i32;
-   |            ^^^^^^ expected `u8`, found `i32`
+   |     ----   ^^^^^^ expected `u8`, found `i32`
+   |     |
+   |     expected because this is `u8`
    |
 help: you can convert `x_u8` from `u8` to `i32`, matching the type of `-1_i32`
    |
@@ -224,7 +272,9 @@ error[E0308]: mismatched types
   --> $DIR/numeric-cast-no-fix.rs:62:15
    |
 LL |     x_usize > -1_i16;
-   |               ^^^^^^ expected `usize`, found `i16`
+   |     -------   ^^^^^^ expected `usize`, found `i16`
+   |     |
+   |     expected because this is `usize`
    |
    = note: `-1_i16` cannot fit into type `usize`
 
@@ -232,7 +282,9 @@ error[E0308]: mismatched types
   --> $DIR/numeric-cast-no-fix.rs:64:14
    |
 LL |     x_u128 > -1_i16;
-   |              ^^^^^^ expected `u128`, found `i16`
+   |     ------   ^^^^^^ expected `u128`, found `i16`
+   |     |
+   |     expected because this is `u128`
    |
    = note: `-1_i16` cannot fit into type `u128`
 
@@ -240,7 +292,9 @@ error[E0308]: mismatched types
   --> $DIR/numeric-cast-no-fix.rs:66:13
    |
 LL |     x_u64 > -1_i16;
-   |             ^^^^^^ expected `u64`, found `i16`
+   |     -----   ^^^^^^ expected `u64`, found `i16`
+   |     |
+   |     expected because this is `u64`
    |
    = note: `-1_i16` cannot fit into type `u64`
 
@@ -248,7 +302,9 @@ error[E0308]: mismatched types
   --> $DIR/numeric-cast-no-fix.rs:68:13
    |
 LL |     x_u32 > -1_i16;
-   |             ^^^^^^ expected `u32`, found `i16`
+   |     -----   ^^^^^^ expected `u32`, found `i16`
+   |     |
+   |     expected because this is `u32`
    |
    = note: `-1_i16` cannot fit into type `u32`
 
@@ -256,7 +312,9 @@ error[E0308]: mismatched types
   --> $DIR/numeric-cast-no-fix.rs:70:13
    |
 LL |     x_u16 > -1_i16;
-   |             ^^^^^^ expected `u16`, found `i16`
+   |     -----   ^^^^^^ expected `u16`, found `i16`
+   |     |
+   |     expected because this is `u16`
    |
    = note: `-1_i16` cannot fit into type `u16`
 
@@ -264,7 +322,9 @@ error[E0308]: mismatched types
   --> $DIR/numeric-cast-no-fix.rs:72:12
    |
 LL |     x_u8 > -1_i16;
-   |            ^^^^^^ expected `u8`, found `i16`
+   |     ----   ^^^^^^ expected `u8`, found `i16`
+   |     |
+   |     expected because this is `u8`
    |
 help: you can convert `x_u8` from `u8` to `i16`, matching the type of `-1_i16`
    |
@@ -275,7 +335,9 @@ error[E0308]: mismatched types
   --> $DIR/numeric-cast-no-fix.rs:75:15
    |
 LL |     x_usize > -1_i8;
-   |               ^^^^^ expected `usize`, found `i8`
+   |     -------   ^^^^^ expected `usize`, found `i8`
+   |     |
+   |     expected because this is `usize`
    |
    = note: `-1_i8` cannot fit into type `usize`
 
@@ -283,7 +345,9 @@ error[E0308]: mismatched types
   --> $DIR/numeric-cast-no-fix.rs:77:14
    |
 LL |     x_u128 > -1_i8;
-   |              ^^^^^ expected `u128`, found `i8`
+   |     ------   ^^^^^ expected `u128`, found `i8`
+   |     |
+   |     expected because this is `u128`
    |
    = note: `-1_i8` cannot fit into type `u128`
 
@@ -291,7 +355,9 @@ error[E0308]: mismatched types
   --> $DIR/numeric-cast-no-fix.rs:79:13
    |
 LL |     x_u64 > -1_i8;
-   |             ^^^^^ expected `u64`, found `i8`
+   |     -----   ^^^^^ expected `u64`, found `i8`
+   |     |
+   |     expected because this is `u64`
    |
    = note: `-1_i8` cannot fit into type `u64`
 
@@ -299,7 +365,9 @@ error[E0308]: mismatched types
   --> $DIR/numeric-cast-no-fix.rs:81:13
    |
 LL |     x_u32 > -1_i8;
-   |             ^^^^^ expected `u32`, found `i8`
+   |     -----   ^^^^^ expected `u32`, found `i8`
+   |     |
+   |     expected because this is `u32`
    |
    = note: `-1_i8` cannot fit into type `u32`
 
@@ -307,7 +375,9 @@ error[E0308]: mismatched types
   --> $DIR/numeric-cast-no-fix.rs:83:13
    |
 LL |     x_u16 > -1_i8;
-   |             ^^^^^ expected `u16`, found `i8`
+   |     -----   ^^^^^ expected `u16`, found `i8`
+   |     |
+   |     expected because this is `u16`
    |
    = note: `-1_i8` cannot fit into type `u16`
 
@@ -315,7 +385,9 @@ error[E0308]: mismatched types
   --> $DIR/numeric-cast-no-fix.rs:85:12
    |
 LL |     x_u8 > -1_i8;
-   |            ^^^^^ expected `u8`, found `i8`
+   |     ----   ^^^^^ expected `u8`, found `i8`
+   |     |
+   |     expected because this is `u8`
    |
    = note: `-1_i8` cannot fit into type `u8`
 
index c1aaad31e81255dc6a36dcfd4866579d24f15cff..f05b0cd65381b5bd399262e3d025f444ac506f12 100644 (file)
@@ -3,10 +3,10 @@ error[E0311]: the parameter type `Self` may not live long enough
    = help: consider adding an explicit lifetime bound `Self: 'a`...
    = note: ...so that the type `Self` will meet its required lifetime bounds...
 note: ...that is required by this bound
-  --> $DIR/object-safety-supertrait-mentions-GAT.rs:9:39
+  --> $DIR/object-safety-supertrait-mentions-GAT.rs:6:15
    |
-LL | trait SuperTrait<T>: for<'a> GatTrait<Gat<'a> = T> {
-   |                                       ^^^^^^^^^^^
+LL |         Self: 'a;
+   |               ^^
 
 error: associated item referring to unboxed trait object for its own trait
   --> $DIR/object-safety-supertrait-mentions-GAT.rs:10:20
diff --git a/src/test/ui/on-unimplemented/sum.rs b/src/test/ui/on-unimplemented/sum.rs
new file mode 100644 (file)
index 0000000..4f1c521
--- /dev/null
@@ -0,0 +1,9 @@
+// <https://github.com/rust-lang/rust/issues/105184>
+
+fn main() {
+    vec![(), ()].iter().sum::<i32>();
+    //~^ ERROR
+
+    vec![(), ()].iter().product::<i32>();
+    //~^ ERROR
+}
diff --git a/src/test/ui/on-unimplemented/sum.stderr b/src/test/ui/on-unimplemented/sum.stderr
new file mode 100644 (file)
index 0000000..c310367
--- /dev/null
@@ -0,0 +1,39 @@
+error[E0277]: a value of type `i32` cannot be made by summing an iterator over elements of type `&()`
+  --> $DIR/sum.rs:4:5
+   |
+LL |     vec![(), ()].iter().sum::<i32>();
+   |     ^^^^^^^^^^^^^^^^^^^ --- required by a bound introduced by this call
+   |     |
+   |     value of type `i32` cannot be made by summing a `std::iter::Iterator<Item=&()>`
+   |
+   = help: the trait `Sum<&()>` is not implemented for `i32`
+   = help: the following other types implement trait `Sum<A>`:
+             <i32 as Sum<&'a i32>>
+             <i32 as Sum>
+note: required by a bound in `std::iter::Iterator::sum`
+  --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
+   |
+LL |         S: Sum<Self::Item>,
+   |            ^^^^^^^^^^^^^^^ required by this bound in `Iterator::sum`
+
+error[E0277]: a value of type `i32` cannot be made by multiplying all elements of type `&()` from an iterator
+  --> $DIR/sum.rs:7:5
+   |
+LL |     vec![(), ()].iter().product::<i32>();
+   |     ^^^^^^^^^^^^^^^^^^^ ------- required by a bound introduced by this call
+   |     |
+   |     value of type `i32` cannot be made by multiplying all elements from a `std::iter::Iterator<Item=&()>`
+   |
+   = help: the trait `Product<&()>` is not implemented for `i32`
+   = help: the following other types implement trait `Product<A>`:
+             <i32 as Product<&'a i32>>
+             <i32 as Product>
+note: required by a bound in `std::iter::Iterator::product`
+  --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
+   |
+LL |         P: Product<Self::Item>,
+   |            ^^^^^^^^^^^^^^^^^^^ required by this bound in `Iterator::product`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
index c77992b2c3406f3b0dbd7037c7cc6025ea201028..7d17ea59647ec043f7eb0b5f071f80442ec4ef5d 100644 (file)
@@ -34,7 +34,9 @@ error[E0308]: mismatched types
   --> $DIR/bare-struct-body.rs:11:14
    |
 LL |     x.val == 42;
-   |              ^^ expected `()`, found integer
+   |     -----    ^^ expected `()`, found integer
+   |     |
+   |     expected because this is `()`
 
 error: aborting due to 3 previous errors
 
index 694b0b6eb028f7498b7b1e60d65388bb8d9a9487..ae243816d7c2d55af0aebf01fa34cc452b2a9b1a 100644 (file)
@@ -123,37 +123,49 @@ error[E0308]: mismatched types
   --> $DIR/chained-comparison-suggestion.rs:4:14
    |
 LL |     1 < 2 <= 3;
-   |              ^ expected `bool`, found integer
+   |     -----    ^ expected `bool`, found integer
+   |     |
+   |     expected because this is `bool`
 
 error[E0308]: mismatched types
   --> $DIR/chained-comparison-suggestion.rs:13:14
    |
 LL |     1 <= 2 < 3;
-   |              ^ expected `bool`, found integer
+   |     ------   ^ expected `bool`, found integer
+   |     |
+   |     expected because this is `bool`
 
 error[E0308]: mismatched types
   --> $DIR/chained-comparison-suggestion.rs:18:15
    |
 LL |     1 <= 2 <= 3;
-   |               ^ expected `bool`, found integer
+   |     ------    ^ expected `bool`, found integer
+   |     |
+   |     expected because this is `bool`
 
 error[E0308]: mismatched types
   --> $DIR/chained-comparison-suggestion.rs:23:14
    |
 LL |     1 > 2 >= 3;
-   |              ^ expected `bool`, found integer
+   |     -----    ^ expected `bool`, found integer
+   |     |
+   |     expected because this is `bool`
 
 error[E0308]: mismatched types
   --> $DIR/chained-comparison-suggestion.rs:36:15
    |
 LL |     1 >= 2 >= 3;
-   |               ^ expected `bool`, found integer
+   |     ------    ^ expected `bool`, found integer
+   |     |
+   |     expected because this is `bool`
 
 error[E0308]: mismatched types
   --> $DIR/chained-comparison-suggestion.rs:49:15
    |
 LL |     1 == 2 == 3;
-   |               ^ expected `bool`, found integer
+   |     ------    ^ expected `bool`, found integer
+   |     |
+   |     expected because this is `bool`
 
 error: aborting due to 17 previous errors
 
index 36709eea17c2144795de5995d944bf091a490b9f..b06f62794c4e3a4632930ed8ed7d90866bac79bd 100644 (file)
@@ -64,4 +64,16 @@ fn asteroids() -> impl FnOnce() -> bool {
     { foo(); } || { true } //~ ERROR E0308
 }
 
+// https://github.com/rust-lang/rust/issues/105179
+fn r#match() -> i32 {
+    (match () { () => 1 }) + match () { () => 1 } //~ ERROR expected expression, found `+`
+    //~^ ERROR mismatched types
+}
+
+// https://github.com/rust-lang/rust/issues/102171
+fn r#unsafe() -> i32 {
+    (unsafe { 1 }) + unsafe { 1 } //~ ERROR expected expression, found `+`
+    //~^ ERROR mismatched types
+}
+
 fn main() {}
index 92bb972b24020e3cc29ce21ef0d4e79d98bafffd..b39d2b88647c0a5d806ce3c4b227801dbe86ee7f 100644 (file)
@@ -64,4 +64,16 @@ fn asteroids() -> impl FnOnce() -> bool {
     { foo() } || { true } //~ ERROR E0308
 }
 
+// https://github.com/rust-lang/rust/issues/105179
+fn r#match() -> i32 {
+    match () { () => 1 } + match () { () => 1 } //~ ERROR expected expression, found `+`
+    //~^ ERROR mismatched types
+}
+
+// https://github.com/rust-lang/rust/issues/102171
+fn r#unsafe() -> i32 {
+    unsafe { 1 } + unsafe { 1 } //~ ERROR expected expression, found `+`
+    //~^ ERROR mismatched types
+}
+
 fn main() {}
index 6da4ac34067e9bc8e74a4e888c1e82f29000a96c..18c8b0b7c506bbb6b0fd069ecb07d2df43ac6e79 100644 (file)
@@ -55,6 +55,28 @@ help: parentheses are required to parse this as an expression
 LL |     ({ true }) | { true }
    |     +        +
 
+error: expected expression, found `+`
+  --> $DIR/expr-as-stmt.rs:69:26
+   |
+LL |     match () { () => 1 } + match () { () => 1 }
+   |                          ^ expected expression
+   |
+help: parentheses are required to parse this as an expression
+   |
+LL |     (match () { () => 1 }) + match () { () => 1 }
+   |     +                    +
+
+error: expected expression, found `+`
+  --> $DIR/expr-as-stmt.rs:75:18
+   |
+LL |     unsafe { 1 } + unsafe { 1 }
+   |                  ^ expected expression
+   |
+help: parentheses are required to parse this as an expression
+   |
+LL |     (unsafe { 1 }) + unsafe { 1 }
+   |     +            +
+
 error[E0308]: mismatched types
   --> $DIR/expr-as-stmt.rs:64:7
    |
@@ -201,7 +223,26 @@ help: parentheses are required to parse this as an expression
 LL |     ({ true }) || { true }
    |     +        +
 
-error: aborting due to 18 previous errors
+error[E0308]: mismatched types
+  --> $DIR/expr-as-stmt.rs:69:5
+   |
+LL |     match () { () => 1 } + match () { () => 1 }
+   |     ^^^^^^^^^^^^^^^^^^^^- help: consider using a semicolon here
+   |     |
+   |     expected `()`, found integer
+
+error[E0308]: mismatched types
+  --> $DIR/expr-as-stmt.rs:75:14
+   |
+LL |     unsafe { 1 } + unsafe { 1 }
+   |              ^ expected `()`, found integer
+   |
+help: you might have meant to return this value
+   |
+LL |     unsafe { return 1; } + unsafe { 1 }
+   |              ++++++  +
+
+error: aborting due to 22 previous errors
 
 Some errors have detailed explanations: E0308, E0600, E0614.
 For more information about an error, try `rustc --explain E0308`.
index bffc881bdc84b84623c84aadab53c60b6ca8b0d7..1edca391e8fd01eb9e6b7e877d7ce4f6ab64f2fe 100644 (file)
@@ -3,6 +3,8 @@ error: unexpected `==`
    |
 LL |     B == 2
    |       ^^ help: try using `=` instead
+   |
+   = help: enum variants can be `Variant`, `Variant = <integer>`, `Variant(Type, ..., TypeN)` or `Variant { fields: Types }`
 
 error: expected item, found `==`
   --> $DIR/issue-101477-enum.rs:6:7
diff --git a/src/test/ui/parser/issue-103869.rs b/src/test/ui/parser/issue-103869.rs
new file mode 100644 (file)
index 0000000..28c442b
--- /dev/null
@@ -0,0 +1,9 @@
+enum VecOrMap{
+    vec: Vec<usize>,
+    //~^ ERROR expected one of `(`, `,`, `=`, `{`, or `}`, found `:`
+    //~| HELP: enum variants can be `Variant`, `Variant = <integer>`, `Variant(Type, ..., TypeN)` or `Variant { fields: Types }`
+    //~| ERROR expected item, found `:`
+    map: HashMap<String,usize>
+}
+
+fn main() {}
diff --git a/src/test/ui/parser/issue-103869.stderr b/src/test/ui/parser/issue-103869.stderr
new file mode 100644 (file)
index 0000000..0b8cd91
--- /dev/null
@@ -0,0 +1,16 @@
+error: expected one of `(`, `,`, `=`, `{`, or `}`, found `:`
+  --> $DIR/issue-103869.rs:2:8
+   |
+LL |     vec: Vec<usize>,
+   |        ^ expected one of `(`, `,`, `=`, `{`, or `}`
+   |
+   = help: enum variants can be `Variant`, `Variant = <integer>`, `Variant(Type, ..., TypeN)` or `Variant { fields: Types }`
+
+error: expected item, found `:`
+  --> $DIR/issue-103869.rs:2:8
+   |
+LL |     vec: Vec<usize>,
+   |        ^ expected item
+
+error: aborting due to 2 previous errors
+
index b1f8674fbdf386609c4c9c70e622286e96dd8ef1..da9e743a0b44ffc73a4f45ef9eb3f2ee0535b63d 100644 (file)
@@ -9,6 +9,7 @@ LL |             $( $t, )*
 LL |     test_macro!(String,);
    |     -------------------- in this macro invocation
    |
+   = help: enum variants can be `Variant`, `Variant = <integer>`, `Variant(Type, ..., TypeN)` or `Variant { fields: Types }`
    = note: this error originates in the macro `test_macro` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: aborting due to previous error
index 49895f3db4dff417b3967215b97a8ef308c8c33c..08b90b365e326db0e796f1b2de0e2efba56651ab 100644 (file)
@@ -2,7 +2,9 @@ error[E0308]: mismatched types
   --> $DIR/pptypedef.rs:4:37
    |
 LL |     let_in(3u32, |i| { assert!(i == 3i32); });
-   |                                     ^^^^ expected `u32`, found `i32`
+   |                                -    ^^^^ expected `u32`, found `i32`
+   |                                |
+   |                                expected because this is `u32`
    |
 help: change the type of the numeric literal from `i32` to `u32`
    |
@@ -13,7 +15,9 @@ error[E0308]: mismatched types
   --> $DIR/pptypedef.rs:8:37
    |
 LL |     let_in(3i32, |i| { assert!(i == 3u32); });
-   |                                     ^^^^ expected `i32`, found `u32`
+   |                                -    ^^^^ expected `i32`, found `u32`
+   |                                |
+   |                                expected because this is `i32`
    |
 help: change the type of the numeric literal from `u32` to `i32`
    |
diff --git a/src/test/ui/print_type_sizes/async.rs b/src/test/ui/print_type_sizes/async.rs
new file mode 100644 (file)
index 0000000..3491ad5
--- /dev/null
@@ -0,0 +1,19 @@
+// compile-flags: -Z print-type-sizes
+// edition:2021
+// build-pass
+// ignore-pass
+
+#![feature(start)]
+
+async fn wait() {}
+
+async fn test(arg: [u8; 8192]) {
+    wait().await;
+    drop(arg);
+}
+
+#[start]
+fn start(_: isize, _: *const *const u8) -> isize {
+    let _ = test([0; 8192]);
+    0
+}
diff --git a/src/test/ui/print_type_sizes/async.stdout b/src/test/ui/print_type_sizes/async.stdout
new file mode 100644 (file)
index 0000000..94ad09e
--- /dev/null
@@ -0,0 +1,34 @@
+print-type-size type: `[async fn body@$DIR/async.rs:10:32: 13:2]`: 16386 bytes, alignment: 1 bytes
+print-type-size     discriminant: 1 bytes
+print-type-size     variant `Suspend0`: 16385 bytes
+print-type-size         field `.arg`: 8192 bytes, offset: 0 bytes, alignment: 1 bytes
+print-type-size         field `.arg`: 8192 bytes
+print-type-size         field `.__awaitee`: 1 bytes
+print-type-size     variant `Unresumed`: 8192 bytes
+print-type-size         field `.arg`: 8192 bytes, offset: 0 bytes, alignment: 1 bytes
+print-type-size     variant `Returned`: 8192 bytes
+print-type-size         field `.arg`: 8192 bytes, offset: 0 bytes, alignment: 1 bytes
+print-type-size     variant `Panicked`: 8192 bytes
+print-type-size         field `.arg`: 8192 bytes, offset: 0 bytes, alignment: 1 bytes
+print-type-size type: `std::mem::ManuallyDrop<[u8; 8192]>`: 8192 bytes, alignment: 1 bytes
+print-type-size     field `.value`: 8192 bytes
+print-type-size type: `std::mem::MaybeUninit<[u8; 8192]>`: 8192 bytes, alignment: 1 bytes
+print-type-size     variant `MaybeUninit`: 8192 bytes
+print-type-size         field `.uninit`: 0 bytes
+print-type-size         field `.value`: 8192 bytes
+print-type-size type: `[async fn body@$DIR/async.rs:8:17: 8:19]`: 1 bytes, alignment: 1 bytes
+print-type-size     discriminant: 1 bytes
+print-type-size     variant `Unresumed`: 0 bytes
+print-type-size     variant `Returned`: 0 bytes
+print-type-size     variant `Panicked`: 0 bytes
+print-type-size type: `std::mem::ManuallyDrop<[async fn body@$DIR/async.rs:8:17: 8:19]>`: 1 bytes, alignment: 1 bytes
+print-type-size     field `.value`: 1 bytes
+print-type-size type: `std::mem::MaybeUninit<[async fn body@$DIR/async.rs:8:17: 8:19]>`: 1 bytes, alignment: 1 bytes
+print-type-size     variant `MaybeUninit`: 1 bytes
+print-type-size         field `.uninit`: 0 bytes
+print-type-size         field `.value`: 1 bytes
+print-type-size type: `std::task::Poll<()>`: 1 bytes, alignment: 1 bytes
+print-type-size     discriminant: 1 bytes
+print-type-size     variant `Ready`: 0 bytes
+print-type-size         field `.0`: 0 bytes
+print-type-size     variant `Pending`: 0 bytes
diff --git a/src/test/ui/print_type_sizes/generator.rs b/src/test/ui/print_type_sizes/generator.rs
new file mode 100644 (file)
index 0000000..a46db61
--- /dev/null
@@ -0,0 +1,20 @@
+// compile-flags: -Z print-type-sizes
+// build-pass
+// ignore-pass
+
+#![feature(start, generators, generator_trait)]
+
+use std::ops::Generator;
+
+fn generator<const C: usize>(array: [u8; C]) -> impl Generator<Yield = (), Return = ()> {
+    move |()| {
+        yield ();
+        let _ = array;
+    }
+}
+
+#[start]
+fn start(_: isize, _: *const *const u8) -> isize {
+    let _ = generator([0; 8192]);
+    0
+}
diff --git a/src/test/ui/print_type_sizes/generator.stdout b/src/test/ui/print_type_sizes/generator.stdout
new file mode 100644 (file)
index 0000000..28d4a6e
--- /dev/null
@@ -0,0 +1,10 @@
+print-type-size type: `[generator@$DIR/generator.rs:10:5: 10:14]`: 8193 bytes, alignment: 1 bytes
+print-type-size     discriminant: 1 bytes
+print-type-size     variant `Unresumed`: 8192 bytes
+print-type-size         field `.array`: 8192 bytes, offset: 0 bytes, alignment: 1 bytes
+print-type-size     variant `Returned`: 8192 bytes
+print-type-size         field `.array`: 8192 bytes, offset: 0 bytes, alignment: 1 bytes
+print-type-size     variant `Panicked`: 8192 bytes
+print-type-size         field `.array`: 8192 bytes, offset: 0 bytes, alignment: 1 bytes
+print-type-size     variant `Suspend0`: 8192 bytes
+print-type-size         field `.array`: 8192 bytes, offset: 0 bytes, alignment: 1 bytes
index 8d0602fa79f02ea06414251afd8437e2f184ac2b..ff20e20d332884d6cb8526651d3143f16b9141cf 100644 (file)
@@ -72,6 +72,5 @@ mod half_public_import {
 
 #[rustc_effective_visibility]
 pub use half_public_import::HalfPublicImport; //~ ERROR Direct: pub, Reexported: pub, Reachable: pub, ReachableThroughImplTrait: pub
-                                              //~^ ERROR Direct: pub, Reexported: pub, Reachable: pub, ReachableThroughImplTrait: pub
 
 fn main() {}
index 6a99afe64fee3f67cd2f410f58929e957a3f435f..046b6095f4e79b0008cb4c01d1884118b69c6a8e 100644 (file)
@@ -124,12 +124,6 @@ error: Direct: pub, Reexported: pub, Reachable: pub, ReachableThroughImplTrait:
 LL | pub use half_public_import::HalfPublicImport;
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: Direct: pub, Reexported: pub, Reachable: pub, ReachableThroughImplTrait: pub
-  --> $DIR/effective_visibilities.rs:74:9
-   |
-LL | pub use half_public_import::HalfPublicImport;
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
 error: Direct: pub(crate), Reexported: pub, Reachable: pub, ReachableThroughImplTrait: pub
   --> $DIR/effective_visibilities.rs:14:13
    |
@@ -142,5 +136,5 @@ error: Direct: pub(crate), Reexported: pub, Reachable: pub, ReachableThroughImpl
 LL |             type B;
    |             ^^^^^^
 
-error: aborting due to 24 previous errors
+error: aborting due to 23 previous errors
 
index bcb54df0ecac75388f3b36ab2cda47f6d197d019..f96939bb6efcee107a0ebd29246c9fcbdb0cd2e4 100644 (file)
@@ -8,21 +8,25 @@ error: macro expansion ignores token `,` and any following
   --> $DIR/attr-invalid-exprs.rs:15:13
    |
 LL |     let _ = #[duplicate] "Hello, world!";
-   |             ^^^^^^^^^^^^- help: you might be missing a semicolon here: `;`
-   |             |
-   |             caused by the macro expansion here
+   |             ^^^^^^^^^^^^ caused by the macro expansion here
    |
    = note: the usage of `duplicate!` is likely invalid in expression context
+help: you might be missing a semicolon here
+   |
+LL |     let _ = #[duplicate]; "Hello, world!";
+   |                         +
 
 error: macro expansion ignores token `,` and any following
   --> $DIR/attr-invalid-exprs.rs:24:9
    |
 LL |         #[duplicate]
-   |         ^^^^^^^^^^^^- help: you might be missing a semicolon here: `;`
-   |         |
-   |         caused by the macro expansion here
+   |         ^^^^^^^^^^^^ caused by the macro expansion here
    |
    = note: the usage of `duplicate!` is likely invalid in expression context
+help: you might be missing a semicolon here
+   |
+LL |         #[duplicate];
+   |                     +
 
 error: aborting due to 3 previous errors
 
index 5531b32362125b4a4ed227dab4a785b9b3cb08d3..9e40e4d9ba63e92d243403451274948859aa7ea0 100644 (file)
@@ -53,19 +53,19 @@ pub fn foo11(input: TokenStream) -> TokenStream { input }
 pub fn foo12(input: TokenStream) -> TokenStream { input }
 
 #[proc_macro_derive(d13, attributes("a"))]
-//~^ ERROR: not a meta item
+//~^ ERROR: attribute must be a meta item, not a literal
 pub fn foo13(input: TokenStream) -> TokenStream { input }
 
 #[proc_macro_derive(d14, attributes(a = ""))]
-//~^ ERROR: must only be one word
+//~^ ERROR: attribute must only be a single word
 pub fn foo14(input: TokenStream) -> TokenStream { input }
 
 #[proc_macro_derive(d15, attributes(m::a))]
-//~^ ERROR: must only be one word
+//~^ ERROR: attribute must only be a single word
 pub fn foo15(input: TokenStream) -> TokenStream { input }
 
 #[proc_macro_derive(d16, attributes(a(b)))]
-//~^ ERROR: must only be one word
+//~^ ERROR: attribute must only be a single word
 pub fn foo16(input: TokenStream) -> TokenStream { input }
 
 #[proc_macro_derive(d17, attributes(self))]
index 021e7cad09b695c7e1bc72cece3b99d61431cbe9..3269aaf7f917eff367e0ac424f85b0aa802e04ec 100644 (file)
@@ -70,25 +70,25 @@ error: attribute must be of form: `attributes(foo, bar)`
 LL | #[proc_macro_derive(d12, attributes)]
    |                          ^^^^^^^^^^
 
-error: not a meta item
+error: attribute must be a meta item, not a literal
   --> $DIR/attribute.rs:55:37
    |
 LL | #[proc_macro_derive(d13, attributes("a"))]
    |                                     ^^^
 
-error: must only be one word
+error: attribute must only be a single word
   --> $DIR/attribute.rs:59:37
    |
 LL | #[proc_macro_derive(d14, attributes(a = ""))]
    |                                     ^^^^^^
 
-error: must only be one word
+error: attribute must only be a single word
   --> $DIR/attribute.rs:63:37
    |
 LL | #[proc_macro_derive(d15, attributes(m::a))]
    |                                     ^^^^
 
-error: must only be one word
+error: attribute must only be a single word
   --> $DIR/attribute.rs:67:37
    |
 LL | #[proc_macro_derive(d16, attributes(a(b)))]
index c6c4695fd9c43ee3093272a895cd3ff6f70b74af..0004f2fe17f01ebfb65aaabbd86b376482eee382 100644 (file)
@@ -26,21 +26,25 @@ error: macro expansion ignores token `hello` and any following
   --> $DIR/expand-expr.rs:115:47
    |
 LL | expand_expr_is!("string", echo_tts!("string"; hello));
-   |                           --------------------^^^^^-- help: you might be missing a semicolon here: `;`
-   |                           |
-   |                           caused by the macro expansion here
+   |                           --------------------^^^^^- caused by the macro expansion here
    |
    = note: the usage of `echo_tts!` is likely invalid in expression context
+help: you might be missing a semicolon here
+   |
+LL | expand_expr_is!("string", echo_tts!("string"; hello););
+   |                                                     +
 
 error: macro expansion ignores token `;` and any following
   --> $DIR/expand-expr.rs:116:44
    |
 LL | expand_expr_is!("string", echo_pm!("string"; hello));
-   |                           -----------------^-------- help: you might be missing a semicolon here: `;`
-   |                           |
-   |                           caused by the macro expansion here
+   |                           -----------------^------- caused by the macro expansion here
    |
    = note: the usage of `echo_pm!` is likely invalid in expression context
+help: you might be missing a semicolon here
+   |
+LL | expand_expr_is!("string", echo_pm!("string"; hello););
+   |                                                    +
 
 error: recursion limit reached while expanding `recursive_expand!`
   --> $DIR/expand-expr.rs:124:16
diff --git a/src/test/ui/query-system/fn-sig-cycle-arity.rs b/src/test/ui/query-system/fn-sig-cycle-arity.rs
new file mode 100644 (file)
index 0000000..7a9b846
--- /dev/null
@@ -0,0 +1,8 @@
+trait Dancer {
+    fn dance(&self) -> _ {
+        //~^ ERROR the placeholder `_` is not allowed within types on item signatures for return types
+        self.dance()
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/query-system/fn-sig-cycle-arity.stderr b/src/test/ui/query-system/fn-sig-cycle-arity.stderr
new file mode 100644 (file)
index 0000000..67e0c25
--- /dev/null
@@ -0,0 +1,9 @@
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for return types
+  --> $DIR/fn-sig-cycle-arity.rs:2:24
+   |
+LL |     fn dance(&self) -> _ {
+   |                        ^ not allowed in type signatures
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0121`.
index 4cbf8869d0c59b4723857e55a21c45fd4adbbb96..070dc844563c9aabca3407b3442117c824d224a3 100644 (file)
@@ -4,7 +4,7 @@ error[E0308]: mismatched types
 LL |     take_range(std::ops::Range { start: 0, end: 1 });
    |     ---------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |     |          |
-   |     |          expected reference, found struct `std::ops::Range`
+   |     |          expected reference, found struct `Range`
    |     |          help: consider borrowing here: `&std::ops::Range { start: 0, end: 1 }`
    |     arguments to this function are incorrect
    |
@@ -22,7 +22,7 @@ error[E0308]: mismatched types
 LL |     take_range(::std::ops::Range { start: 0, end: 1 });
    |     ---------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |     |          |
-   |     |          expected reference, found struct `std::ops::Range`
+   |     |          expected reference, found struct `Range`
    |     |          help: consider borrowing here: `&::std::ops::Range { start: 0, end: 1 }`
    |     arguments to this function are incorrect
    |
index 38df6e14496a626ef873498e4ae32f756c25cd3c..9eec169404cdf2e72373789c1fc88fdb1f222d6e 100644 (file)
@@ -4,7 +4,7 @@ error[E0308]: mismatched types
 LL |     take_range(0..1);
    |     ---------- ^^^^
    |     |          |
-   |     |          expected reference, found struct `std::ops::Range`
+   |     |          expected reference, found struct `Range`
    |     |          help: consider borrowing here: `&(0..1)`
    |     arguments to this function are incorrect
    |
index 6badd998f9617ab4af6e8306e4f8199218f60d4d..d08d9b1345d4ad516edfeedd474037174d985e6c 100644 (file)
@@ -4,7 +4,7 @@ error[E0308]: mismatched types
 LL |     demo(tell(1)..tell(10));
    |     ---- ^^^^^^^^^^^^^^^^^
    |     |    |
-   |     |    expected reference, found struct `std::ops::Range`
+   |     |    expected `&Range<usize>`, found struct `Range`
    |     |    help: consider borrowing here: `&(tell(1)..tell(10))`
    |     arguments to this function are incorrect
    |
@@ -22,7 +22,7 @@ error[E0308]: mismatched types
 LL |     demo(1..10);
    |     ---- ^^^^^
    |     |    |
-   |     |    expected reference, found struct `std::ops::Range`
+   |     |    expected `&Range<usize>`, found struct `Range`
    |     |    help: consider borrowing here: `&(1..10)`
    |     arguments to this function are incorrect
    |
index a814003aebf20c08a43bfdd8f56c288493e0753e..2e075a1b9e8bb2129df4f9a58a49383832c82288 100644 (file)
@@ -18,7 +18,7 @@ fn main() {
     let index_deref_ref = &raw const SLICE_REF[1];
 
     let x = 0;
-    let ascribe_ref = &raw const (x: i32);
-    let ascribe_deref = &raw const (*ARRAY_REF: [i32; 2]);
-    let ascribe_index_deref = &raw const (ARRAY_REF[0]: i32);
+    let ascribe_ref = &raw const type_ascribe!(x, i32);
+    let ascribe_deref = &raw const type_ascribe!(*ARRAY_REF, [i32; 2]);
+    let ascribe_index_deref = &raw const type_ascribe!(ARRAY_REF[0], i32);
 }
index 32df56468da172e95894f85e6cd187c77ab3f7a7..10e47cb34c58db9e83c9d5d642d914b6bd90f575 100644 (file)
@@ -8,24 +8,24 @@
 const ARRAY: [i32; 2] = [1, 2];
 
 fn main() {
-    let ref_expr = &raw const 2;                        //~ ERROR cannot take address
-    let mut_ref_expr = &raw mut 3;                      //~ ERROR cannot take address
-    let ref_const = &raw const FOUR;                    //~ ERROR cannot take address
-    let mut_ref_const = &raw mut FOUR;                  //~ ERROR cannot take address
-
-    let field_ref_expr = &raw const (1, 2).0;           //~ ERROR cannot take address
-    let mut_field_ref_expr = &raw mut (1, 2).0;         //~ ERROR cannot take address
-    let field_ref = &raw const PAIR.0;                  //~ ERROR cannot take address
-    let mut_field_ref = &raw mut PAIR.0;                //~ ERROR cannot take address
-
-    let index_ref_expr = &raw const [1, 2][0];          //~ ERROR cannot take address
-    let mut_index_ref_expr = &raw mut [1, 2][0];        //~ ERROR cannot take address
-    let index_ref = &raw const ARRAY[0];                //~ ERROR cannot take address
-    let mut_index_ref = &raw mut ARRAY[1];              //~ ERROR cannot take address
-
-    let ref_ascribe = &raw const (2: i32);              //~ ERROR cannot take address
-    let mut_ref_ascribe = &raw mut (3: i32);            //~ ERROR cannot take address
-
-    let ascribe_field_ref = &raw const (PAIR.0: i32);   //~ ERROR cannot take address
-    let ascribe_index_ref = &raw mut (ARRAY[0]: i32);   //~ ERROR cannot take address
+    let ref_expr = &raw const 2;                                    //~ ERROR cannot take address
+    let mut_ref_expr = &raw mut 3;                                  //~ ERROR cannot take address
+    let ref_const = &raw const FOUR;                                //~ ERROR cannot take address
+    let mut_ref_const = &raw mut FOUR;                              //~ ERROR cannot take address
+
+    let field_ref_expr = &raw const (1, 2).0;                       //~ ERROR cannot take address
+    let mut_field_ref_expr = &raw mut (1, 2).0;                     //~ ERROR cannot take address
+    let field_ref = &raw const PAIR.0;                              //~ ERROR cannot take address
+    let mut_field_ref = &raw mut PAIR.0;                            //~ ERROR cannot take address
+
+    let index_ref_expr = &raw const [1, 2][0];                      //~ ERROR cannot take address
+    let mut_index_ref_expr = &raw mut [1, 2][0];                    //~ ERROR cannot take address
+    let index_ref = &raw const ARRAY[0];                            //~ ERROR cannot take address
+    let mut_index_ref = &raw mut ARRAY[1];                          //~ ERROR cannot take address
+
+    let ref_ascribe = &raw const type_ascribe!(2, i32);             //~ ERROR cannot take address
+    let mut_ref_ascribe = &raw mut type_ascribe!(3, i32);           //~ ERROR cannot take address
+
+    let ascribe_field_ref = &raw const type_ascribe!(PAIR.0, i32);  //~ ERROR cannot take address
+    let ascribe_index_ref = &raw mut type_ascribe!(ARRAY[0], i32);  //~ ERROR cannot take address
 }
index 80dea76d5953b1c5243863abae85be3825237955..b96661625170f264dfc9bda36e564cc28c9c3b8d 100644 (file)
@@ -73,26 +73,26 @@ LL |     let mut_index_ref = &raw mut ARRAY[1];
 error[E0745]: cannot take address of a temporary
   --> $DIR/raw-ref-temp.rs:26:34
    |
-LL |     let ref_ascribe = &raw const (2: i32);
-   |                                  ^^^^^^^^ temporary value
+LL |     let ref_ascribe = &raw const type_ascribe!(2, i32);
+   |                                  ^^^^^^^^^^^^^^^^^^^^^ temporary value
 
 error[E0745]: cannot take address of a temporary
   --> $DIR/raw-ref-temp.rs:27:36
    |
-LL |     let mut_ref_ascribe = &raw mut (3: i32);
-   |                                    ^^^^^^^^ temporary value
+LL |     let mut_ref_ascribe = &raw mut type_ascribe!(3, i32);
+   |                                    ^^^^^^^^^^^^^^^^^^^^^ temporary value
 
 error[E0745]: cannot take address of a temporary
   --> $DIR/raw-ref-temp.rs:29:40
    |
-LL |     let ascribe_field_ref = &raw const (PAIR.0: i32);
-   |                                        ^^^^^^^^^^^^^ temporary value
+LL |     let ascribe_field_ref = &raw const type_ascribe!(PAIR.0, i32);
+   |                                        ^^^^^^^^^^^^^^^^^^^^^^^^^^ temporary value
 
 error[E0745]: cannot take address of a temporary
   --> $DIR/raw-ref-temp.rs:30:38
    |
-LL |     let ascribe_index_ref = &raw mut (ARRAY[0]: i32);
-   |                                      ^^^^^^^^^^^^^^^ temporary value
+LL |     let ascribe_index_ref = &raw mut type_ascribe!(ARRAY[0], i32);
+   |                                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ temporary value
 
 error: aborting due to 16 previous errors
 
index 8d32397b54248a8479e9c6fc7cc29af55d22f008..1ceb2f85971602c13fbfac0d6551ba35f9745988 100644 (file)
@@ -6,7 +6,7 @@
 
 fn a() {
     // the cast is unreachable:
-    let x = {return}: !; //~ ERROR unreachable
+    let x = type_ascribe!({return}, !); //~ ERROR unreachable
 }
 
 fn main() { }
index c56c64be721fee20e7002ff40be516ee7596be2c..3cb4a32e02fac4011ff916ca6831d8af431b6b9d 100644 (file)
@@ -1,10 +1,10 @@
 error: unreachable expression
   --> $DIR/expr_type.rs:9:13
    |
-LL |     let x = {return}: !;
-   |             ^------^^^^
-   |             ||
-   |             |any code following this expression is unreachable
+LL |     let x = type_ascribe!({return}, !);
+   |             ^^^^^^^^^^^^^^^------^^^^^
+   |             |              |
+   |             |              any code following this expression is unreachable
    |             unreachable expression
    |
 note: the lint level is defined here
index 4d00a7083137782aba899be905d2dd4e9d34033e..dde8ad1b6b327615fe66c1c2c75a644275dd3477 100644 (file)
@@ -12,7 +12,7 @@ LL |     func(&mut iter.map(|x| x + 1))
 error[E0275]: overflow evaluating the requirement `Map<&mut Map<&mut Map<&mut Map<..., ...>, ...>, ...>, ...>: Iterator`
    |
    = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`issue_83150`)
-   = note: required for `&mut Map<&mut Map<&mut Map<..., ...>, ...>, ...>` to implement `Iterator`
+   = note: required for `&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<..., ...>, ...>, ...>, ...>, ...>, ...>, ...>` to implement `Iterator`
    = note: the full type name has been written to '$TEST_BUILD_DIR/recursion/issue-83150/issue-83150.long-type-hash.txt'
 
 error: aborting due to previous error; 1 warning emitted
index e567d5c2723f2c2b631730abe978dbaa380b09ac..88b1c1396516d497870ab47a559636999fccca90 100644 (file)
@@ -22,11 +22,11 @@ fn good_generic_fn<T>() {
 // This should fail because `T` ends up in the upvars of the closure.
 fn bad_generic_fn<T: Copy>(t: T) {
     assert_static(opaque(async move { t; }).next());
-    //~^ ERROR the associated type `<impl Iterator as Iterator>::Item` may not live long enough
+    //~^ ERROR the parameter type `T` may not live long enough
     assert_static(opaque(move || { t; }).next());
     //~^ ERROR the associated type `<impl Iterator as Iterator>::Item` may not live long enough
     assert_static(opaque(opaque(async move { t; }).next()).next());
-    //~^ ERROR the associated type `<impl Iterator as Iterator>::Item` may not live long enough
+    //~^ ERROR the parameter type `T` may not live long enough
 }
 
 fn main() {}
index c08f1059ebf58278b7ce88edc8127f5e867f33da..907964aaf379e5c27b9ecfdf665558f77dfd2380 100644 (file)
@@ -1,11 +1,13 @@
-error[E0310]: the associated type `<impl Iterator as Iterator>::Item` may not live long enough
+error[E0310]: the parameter type `T` may not live long enough
   --> $DIR/closure-in-projection-issue-97405.rs:24:5
    |
 LL |     assert_static(opaque(async move { t; }).next());
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
    |
-   = help: consider adding an explicit lifetime bound `<impl Iterator as Iterator>::Item: 'static`...
-   = note: ...so that the type `<impl Iterator as Iterator>::Item` will meet its required lifetime bounds
+help: consider adding an explicit lifetime bound...
+   |
+LL | fn bad_generic_fn<T: Copy + 'static>(t: T) {
+   |                           +++++++++
 
 error[E0310]: the associated type `<impl Iterator as Iterator>::Item` may not live long enough
   --> $DIR/closure-in-projection-issue-97405.rs:26:5
@@ -16,14 +18,16 @@ LL |     assert_static(opaque(move || { t; }).next());
    = help: consider adding an explicit lifetime bound `<impl Iterator as Iterator>::Item: 'static`...
    = note: ...so that the type `<impl Iterator as Iterator>::Item` will meet its required lifetime bounds
 
-error[E0310]: the associated type `<impl Iterator as Iterator>::Item` may not live long enough
+error[E0310]: the parameter type `T` may not live long enough
   --> $DIR/closure-in-projection-issue-97405.rs:28:5
    |
 LL |     assert_static(opaque(opaque(async move { t; }).next()).next());
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
    |
-   = help: consider adding an explicit lifetime bound `<impl Iterator as Iterator>::Item: 'static`...
-   = note: ...so that the type `<impl Iterator as Iterator>::Item` will meet its required lifetime bounds
+help: consider adding an explicit lifetime bound...
+   |
+LL | fn bad_generic_fn<T: Copy + 'static>(t: T) {
+   |                           +++++++++
 
 error: aborting due to 3 previous errors
 
index e0a1164211a2cad83dacf482db3542e60eb791e7..fd71248d9cb458fc53300679e1d72ea404b778e1 100644 (file)
@@ -1,3 +1,4 @@
+// normalize-stderr-test: "long-type-\d+" -> "long-type-hash"
 use std::cell::Cell;
 
 #[rustfmt::skip]
index 31b855c36bead701fb95d1399bda114653a697b5..157850693ab506ad96fd63ebed1062efe6ac83c5 100644 (file)
@@ -1,5 +1,5 @@
 error[E0308]: mismatched types
-  --> $DIR/issue-102374.rs:16:5
+  --> $DIR/issue-102374.rs:17:5
    |
 LL | ) -> i32 {
    |      --- expected `i32` because of return type
@@ -7,7 +7,8 @@ LL |     f
    |     ^ expected `i32`, found fn pointer
    |
    = note:    expected type `i32`
-           found fn pointer `for<'z1, 'a, 'b, 'c, 'd, 'e, 'f, 'g, 'h, 'i, 'j, 'k, 'l, 'm, 'n, 'o, 'p, 'q, 'r, 's, 't, 'u, 'v, 'w, 'x, 'y, 'z, 'z0> fn(Cell<(&'z1 i32, &'a i32, &'b i32, &'c i32, &'d i32, &'e i32, &'f i32, &'g i32, &'h i32, &'i i32, &'j i32, &'k i32, &'l i32, &'m i32, &'n i32, &'o i32, &'p i32, &'q i32, &'r i32, &'s i32, &'t i32, &'u i32, &'v i32, &'w i32, &'x i32, &'y i32, &'z i32, &'z0 i32)>)`
+           found fn pointer `for<'z1, 'a, 'b, 'c, 'd, 'e, 'f, 'g, 'h, 'i, 'j, 'k, 'l, 'm, 'n, 'o, 'p, 'q, 'r, 's, 't, 'u, 'v, 'w, 'x, 'y, 'z, 'z0> fn(Cell<...>)`
+           the full type name has been written to '$TEST_BUILD_DIR/regions/issue-102374/issue-102374.long-type-hash.txt'
 
 error: aborting due to previous error
 
index 581a6619814601a24250cb80b383d82121a0ba7f..558760c6793ab08dc34bdde3589725466ba53d91 100644 (file)
@@ -1,15 +1,15 @@
-error[E0433]: failed to resolve: use of undeclared crate or module `thing`
-  --> $DIR/bad-module.rs:2:15
-   |
-LL |     let foo = thing::len(Vec::new());
-   |               ^^^^^ use of undeclared crate or module `thing`
-
 error[E0433]: failed to resolve: use of undeclared crate or module `foo`
   --> $DIR/bad-module.rs:5:15
    |
 LL |     let foo = foo::bar::baz();
    |               ^^^ use of undeclared crate or module `foo`
 
+error[E0433]: failed to resolve: use of undeclared crate or module `thing`
+  --> $DIR/bad-module.rs:2:15
+   |
+LL |     let foo = thing::len(Vec::new());
+   |               ^^^^^ use of undeclared crate or module `thing`
+
 error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0433`.
diff --git a/src/test/ui/resolve/issue-101749-2.rs b/src/test/ui/resolve/issue-101749-2.rs
new file mode 100644 (file)
index 0000000..4d3d469
--- /dev/null
@@ -0,0 +1,16 @@
+struct Rectangle {
+    width: i32,
+    height: i32,
+}
+impl Rectangle {
+    fn new(width: i32, height: i32) -> Self {
+        Self { width, height }
+    }
+}
+
+fn main() {
+    let rect = Rectangle::new(3, 4);
+    // `area` is not implemented for `Rectangle`, so this should not suggest
+    let _ = rect::area();
+    //~^ ERROR failed to resolve: use of undeclared crate or module `rect`
+}
diff --git a/src/test/ui/resolve/issue-101749-2.stderr b/src/test/ui/resolve/issue-101749-2.stderr
new file mode 100644 (file)
index 0000000..370d4b1
--- /dev/null
@@ -0,0 +1,9 @@
+error[E0433]: failed to resolve: use of undeclared crate or module `rect`
+  --> $DIR/issue-101749-2.rs:14:13
+   |
+LL |     let _ = rect::area();
+   |             ^^^^ use of undeclared crate or module `rect`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0433`.
diff --git a/src/test/ui/resolve/issue-101749.fixed b/src/test/ui/resolve/issue-101749.fixed
new file mode 100644 (file)
index 0000000..3e55442
--- /dev/null
@@ -0,0 +1,19 @@
+// run-rustfix
+struct Rectangle {
+    width: i32,
+    height: i32,
+}
+impl Rectangle {
+    fn new(width: i32, height: i32) -> Self {
+        Self { width, height }
+    }
+    fn area(&self) -> i32 {
+        self.height * self.width
+    }
+}
+
+fn main() {
+    let rect = Rectangle::new(3, 4);
+    let _ = rect.area();
+    //~^ ERROR failed to resolve: use of undeclared crate or module `rect`
+}
diff --git a/src/test/ui/resolve/issue-101749.rs b/src/test/ui/resolve/issue-101749.rs
new file mode 100644 (file)
index 0000000..fd67cca
--- /dev/null
@@ -0,0 +1,19 @@
+// run-rustfix
+struct Rectangle {
+    width: i32,
+    height: i32,
+}
+impl Rectangle {
+    fn new(width: i32, height: i32) -> Self {
+        Self { width, height }
+    }
+    fn area(&self) -> i32 {
+        self.height * self.width
+    }
+}
+
+fn main() {
+    let rect = Rectangle::new(3, 4);
+    let _ = rect::area();
+    //~^ ERROR failed to resolve: use of undeclared crate or module `rect`
+}
diff --git a/src/test/ui/resolve/issue-101749.stderr b/src/test/ui/resolve/issue-101749.stderr
new file mode 100644 (file)
index 0000000..dd29d7f
--- /dev/null
@@ -0,0 +1,14 @@
+error[E0433]: failed to resolve: use of undeclared crate or module `rect`
+  --> $DIR/issue-101749.rs:17:13
+   |
+LL |     let _ = rect::area();
+   |             ^^^^ use of undeclared crate or module `rect`
+   |
+help: you may have meant to call an instance method
+   |
+LL |     let _ = rect.area();
+   |                 ~
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0433`.
diff --git a/src/test/ui/resolve/issue-105069.rs b/src/test/ui/resolve/issue-105069.rs
new file mode 100644 (file)
index 0000000..73455cf
--- /dev/null
@@ -0,0 +1,11 @@
+use self::A::*;
+use V; //~ ERROR `V` is ambiguous
+use self::B::*;
+enum A {
+    V
+}
+enum B {
+    V
+}
+
+fn main() {}
diff --git a/src/test/ui/resolve/issue-105069.stderr b/src/test/ui/resolve/issue-105069.stderr
new file mode 100644 (file)
index 0000000..1e6c9c6
--- /dev/null
@@ -0,0 +1,21 @@
+error[E0659]: `V` is ambiguous
+  --> $DIR/issue-105069.rs:2:5
+   |
+LL | use V;
+   |     ^ ambiguous name
+   |
+   = note: ambiguous because of multiple potential import sources
+note: `V` could refer to the variant imported here
+  --> $DIR/issue-105069.rs:1:5
+   |
+LL | use self::A::*;
+   |     ^^^^^^^^^^
+note: `V` could also refer to the variant imported here
+  --> $DIR/issue-105069.rs:3:5
+   |
+LL | use self::B::*;
+   |     ^^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0659`.
index 7e539d258048e03989eb25fa94c9fbfac73baada..82f5a1d5b57b3a167741b4600fe18a6dc9486846 100644 (file)
@@ -1,15 +1,3 @@
-error[E0433]: failed to resolve: `Self` is only available in impls, traits, and type definitions
-  --> $DIR/issue-24968.rs:21:19
-   |
-LL | const FOO2: u32 = Self::bar();
-   |                   ^^^^ `Self` is only available in impls, traits, and type definitions
-
-error[E0433]: failed to resolve: `Self` is only available in impls, traits, and type definitions
-  --> $DIR/issue-24968.rs:27:22
-   |
-LL | static FOO_S2: u32 = Self::bar();
-   |                      ^^^^ `Self` is only available in impls, traits, and type definitions
-
 error[E0411]: cannot find type `Self` in this scope
   --> $DIR/issue-24968.rs:3:11
    |
@@ -51,6 +39,18 @@ LL | static FOO_S: Self = 0;
    |        |
    |        `Self` not allowed in a static item
 
+error[E0433]: failed to resolve: `Self` is only available in impls, traits, and type definitions
+  --> $DIR/issue-24968.rs:21:19
+   |
+LL | const FOO2: u32 = Self::bar();
+   |                   ^^^^ `Self` is only available in impls, traits, and type definitions
+
+error[E0433]: failed to resolve: `Self` is only available in impls, traits, and type definitions
+  --> $DIR/issue-24968.rs:27:22
+   |
+LL | static FOO_S2: u32 = Self::bar();
+   |                      ^^^^ `Self` is only available in impls, traits, and type definitions
+
 error: aborting due to 7 previous errors
 
 Some errors have detailed explanations: E0411, E0433.
index ff7cf531c06dd9bbedf494cb9b1786c0c00348ea..89b69e1409967544f917a7bb296e3843210dc5e0 100644 (file)
@@ -1,3 +1,24 @@
+error[E0433]: failed to resolve: could not find `Struc` in `module`
+  --> $DIR/typo-suggestion-mistyped-in-path.rs:35:13
+   |
+LL |     module::Struc::foo();
+   |             ^^^^^
+   |             |
+   |             could not find `Struc` in `module`
+   |             help: a struct with a similar name exists: `Struct`
+
+error[E0599]: no function or associated item named `fob` found for struct `Struct` in the current scope
+  --> $DIR/typo-suggestion-mistyped-in-path.rs:23:13
+   |
+LL | struct Struct;
+   | ------------- function or associated item `fob` not found for this struct
+...
+LL |     Struct::fob();
+   |             ^^^
+   |             |
+   |             function or associated item not found in `Struct`
+   |             help: there is an associated function with a similar name: `foo`
+
 error[E0433]: failed to resolve: use of undeclared type `Struc`
   --> $DIR/typo-suggestion-mistyped-in-path.rs:27:5
    |
@@ -18,15 +39,6 @@ help: there is a crate or module with a similar name
 LL |     module::foo();
    |     ~~~~~~
 
-error[E0433]: failed to resolve: could not find `Struc` in `module`
-  --> $DIR/typo-suggestion-mistyped-in-path.rs:35:13
-   |
-LL |     module::Struc::foo();
-   |             ^^^^^
-   |             |
-   |             could not find `Struc` in `module`
-   |             help: a struct with a similar name exists: `Struct`
-
 error[E0433]: failed to resolve: use of undeclared type `Trai`
   --> $DIR/typo-suggestion-mistyped-in-path.rs:39:5
    |
@@ -36,18 +48,6 @@ LL |     Trai::foo();
    |     use of undeclared type `Trai`
    |     help: a trait with a similar name exists: `Trait`
 
-error[E0599]: no function or associated item named `fob` found for struct `Struct` in the current scope
-  --> $DIR/typo-suggestion-mistyped-in-path.rs:23:13
-   |
-LL | struct Struct;
-   | ------------- function or associated item `fob` not found for this struct
-...
-LL |     Struct::fob();
-   |             ^^^
-   |             |
-   |             function or associated item not found in `Struct`
-   |             help: there is an associated function with a similar name: `foo`
-
 error: aborting due to 5 previous errors
 
 Some errors have detailed explanations: E0433, E0599.
index 58cb659e822035b2bf4fcba5f1cea7f74f7de426..54ad853831f368bbf1dcba37ee673abfd8cec7d4 100644 (file)
@@ -1,9 +1,3 @@
-error[E0433]: failed to resolve: use of undeclared type `GooMap`
-  --> $DIR/use_suggestion.rs:3:14
-   |
-LL |     let x2 = GooMap::new();
-   |              ^^^^^^ use of undeclared type `GooMap`
-
 error[E0433]: failed to resolve: use of undeclared type `HashMap`
   --> $DIR/use_suggestion.rs:2:14
    |
@@ -32,6 +26,12 @@ error[E0412]: cannot find type `GooMap` in this scope
 LL |     let y2: GooMap;
    |             ^^^^^^ not found in this scope
 
+error[E0433]: failed to resolve: use of undeclared type `GooMap`
+  --> $DIR/use_suggestion.rs:3:14
+   |
+LL |     let x2 = GooMap::new();
+   |              ^^^^^^ use of undeclared type `GooMap`
+
 error: aborting due to 4 previous errors
 
 Some errors have detailed explanations: E0412, E0433.
index 2c3610fb24d4e952e72299ca597ea1e8b6760b4d..f46e088b85f7201a46911fa4b19092bf6d48469d 100644 (file)
@@ -12,7 +12,6 @@
 // edition:2018
 
 fn main() {
-    let _ = foo(true);
 }
 
 fn foo(x: bool) -> Result<f64, i32> {
@@ -30,3 +29,19 @@ async fn bar(x: bool) -> Result<f64, i32> {
     }
     Ok(42.0)
 }
+
+trait Identity {
+    type Out;
+}
+
+impl<T> Identity for T {
+    type Out = T;
+}
+
+async fn foo2() -> i32 {
+    if true {
+        1i32 //~ ERROR mismatched types
+            //| HELP you might have meant to return this value
+    }
+    0
+}
index dec1cbc4624ef5bece1d9262d612b21663ccb1e7..9183b4599ba6dafb238f94d2aba435476ba30887 100644 (file)
@@ -1,5 +1,5 @@
 error[E0308]: mismatched types
-  --> $DIR/tail-expr-as-potential-return.rs:28:9
+  --> $DIR/tail-expr-as-potential-return.rs:27:9
    |
 LL | /     if x {
 LL | |         Err(42)
@@ -16,7 +16,22 @@ LL |         return Err(42);
    |         ++++++        +
 
 error[E0308]: mismatched types
-  --> $DIR/tail-expr-as-potential-return.rs:20:9
+  --> $DIR/tail-expr-as-potential-return.rs:43:9
+   |
+LL | /     if true {
+LL | |         1i32
+   | |         ^^^^ expected `()`, found `i32`
+LL | |             //| HELP you might have meant to return this value
+LL | |     }
+   | |_____- expected this to be `()`
+   |
+help: you might have meant to return this value
+   |
+LL |         return 1i32;
+   |         ++++++     +
+
+error[E0308]: mismatched types
+  --> $DIR/tail-expr-as-potential-return.rs:19:9
    |
 LL | /     if x {
 LL | |         Err(42)
@@ -32,6 +47,6 @@ help: you might have meant to return this value
 LL |         return Err(42);
    |         ++++++        +
 
-error: aborting due to 2 previous errors
+error: aborting due to 3 previous errors
 
 For more information about this error, try `rustc --explain E0308`.
index 6b7d94603b567d889aff97f257d49b29d09c257c..a8deb8a7550bc5e5ea8e7ec586386ec431061595 100644 (file)
@@ -5,7 +5,7 @@ struct Foo {
 
 impl PartialEq for Foo {
     fn eq(&self, _: &Foo) -> bool {
-        false // ha ha sucker!
+        false // ha ha!
     }
 }
 
index 91c001151803a35d8fe341619c90db05b4e71002..3028f8dbdbf771e947270f6fbfa874a561dcaf7f 100644 (file)
@@ -1516,7 +1516,7 @@ error[E0308]: mismatched types
   --> $DIR/disallowed-positions.rs:157:8
    |
 LL |     if true..(let 0 = 0) {}
-   |        ^^^^^^^^^^^^^^^^^ expected `bool`, found struct `std::ops::Range`
+   |        ^^^^^^^^^^^^^^^^^ expected `bool`, found struct `Range`
    |
    = note: expected type `bool`
             found struct `std::ops::Range<bool>`
@@ -1545,7 +1545,7 @@ error[E0308]: mismatched types
 LL |     if let Range { start: _, end: _ } = true..true && false {}
    |            ^^^^^^^^^^^^^^^^^^^^^^^^^^   ---- this expression has type `bool`
    |            |
-   |            expected `bool`, found struct `std::ops::Range`
+   |            expected `bool`, found struct `Range`
    |
    = note: expected type `bool`
             found struct `std::ops::Range<_>`
@@ -1554,7 +1554,7 @@ error[E0308]: mismatched types
   --> $DIR/disallowed-positions.rs:171:8
    |
 LL |     if let Range { start: _, end: _ } = true..true && false {}
-   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `bool`, found struct `std::ops::Range`
+   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `bool`, found struct `Range`
    |
    = note: expected type `bool`
             found struct `std::ops::Range<bool>`
@@ -1565,7 +1565,7 @@ error[E0308]: mismatched types
 LL |     if let Range { start: _, end: _ } = true..true || false {}
    |            ^^^^^^^^^^^^^^^^^^^^^^^^^^   ---- this expression has type `bool`
    |            |
-   |            expected `bool`, found struct `std::ops::Range`
+   |            expected `bool`, found struct `Range`
    |
    = note: expected type `bool`
             found struct `std::ops::Range<_>`
@@ -1574,7 +1574,7 @@ error[E0308]: mismatched types
   --> $DIR/disallowed-positions.rs:175:8
    |
 LL |     if let Range { start: _, end: _ } = true..true || false {}
-   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `bool`, found struct `std::ops::Range`
+   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `bool`, found struct `Range`
    |
    = note: expected type `bool`
             found struct `std::ops::Range<bool>`
@@ -1585,7 +1585,7 @@ error[E0308]: mismatched types
 LL |     if let Range { start: F, end } = F..|| true {}
    |            ^^^^^^^^^^^^^^^^^^^^^^^   - this expression has type `fn() -> bool`
    |            |
-   |            expected fn pointer, found struct `std::ops::Range`
+   |            expected fn pointer, found struct `Range`
    |
    = note: expected fn pointer `fn() -> bool`
                   found struct `std::ops::Range<_>`
@@ -1607,7 +1607,7 @@ error[E0308]: mismatched types
   --> $DIR/disallowed-positions.rs:182:8
    |
 LL |     if let Range { start: F, end } = F..|| true {}
-   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `bool`, found struct `std::ops::Range`
+   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `bool`, found struct `Range`
    |
    = note: expected type `bool`
             found struct `std::ops::Range<bool>`
@@ -1618,7 +1618,7 @@ error[E0308]: mismatched types
 LL |     if let Range { start: true, end } = t..&&false {}
    |            ^^^^^^^^^^^^^^^^^^^^^^^^^^   - this expression has type `&&bool`
    |            |
-   |            expected `bool`, found struct `std::ops::Range`
+   |            expected `bool`, found struct `Range`
    |
    = note: expected type `bool`
             found struct `std::ops::Range<_>`
@@ -1639,7 +1639,7 @@ error[E0308]: mismatched types
   --> $DIR/disallowed-positions.rs:190:8
    |
 LL |     if let Range { start: true, end } = t..&&false {}
-   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `bool`, found struct `std::ops::Range`
+   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `bool`, found struct `Range`
    |
    = note: expected type `bool`
             found struct `std::ops::Range<bool>`
@@ -1710,7 +1710,7 @@ error[E0308]: mismatched types
   --> $DIR/disallowed-positions.rs:249:11
    |
 LL |     while true..(let 0 = 0) {}
-   |           ^^^^^^^^^^^^^^^^^ expected `bool`, found struct `std::ops::Range`
+   |           ^^^^^^^^^^^^^^^^^ expected `bool`, found struct `Range`
    |
    = note: expected type `bool`
             found struct `std::ops::Range<bool>`
@@ -1739,7 +1739,7 @@ error[E0308]: mismatched types
 LL |     while let Range { start: _, end: _ } = true..true && false {}
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^^   ---- this expression has type `bool`
    |               |
-   |               expected `bool`, found struct `std::ops::Range`
+   |               expected `bool`, found struct `Range`
    |
    = note: expected type `bool`
             found struct `std::ops::Range<_>`
@@ -1748,7 +1748,7 @@ error[E0308]: mismatched types
   --> $DIR/disallowed-positions.rs:263:11
    |
 LL |     while let Range { start: _, end: _ } = true..true && false {}
-   |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `bool`, found struct `std::ops::Range`
+   |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `bool`, found struct `Range`
    |
    = note: expected type `bool`
             found struct `std::ops::Range<bool>`
@@ -1759,7 +1759,7 @@ error[E0308]: mismatched types
 LL |     while let Range { start: _, end: _ } = true..true || false {}
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^^   ---- this expression has type `bool`
    |               |
-   |               expected `bool`, found struct `std::ops::Range`
+   |               expected `bool`, found struct `Range`
    |
    = note: expected type `bool`
             found struct `std::ops::Range<_>`
@@ -1768,7 +1768,7 @@ error[E0308]: mismatched types
   --> $DIR/disallowed-positions.rs:267:11
    |
 LL |     while let Range { start: _, end: _ } = true..true || false {}
-   |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `bool`, found struct `std::ops::Range`
+   |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `bool`, found struct `Range`
    |
    = note: expected type `bool`
             found struct `std::ops::Range<bool>`
@@ -1779,7 +1779,7 @@ error[E0308]: mismatched types
 LL |     while let Range { start: F, end } = F..|| true {}
    |               ^^^^^^^^^^^^^^^^^^^^^^^   - this expression has type `fn() -> bool`
    |               |
-   |               expected fn pointer, found struct `std::ops::Range`
+   |               expected fn pointer, found struct `Range`
    |
    = note: expected fn pointer `fn() -> bool`
                   found struct `std::ops::Range<_>`
@@ -1801,7 +1801,7 @@ error[E0308]: mismatched types
   --> $DIR/disallowed-positions.rs:274:11
    |
 LL |     while let Range { start: F, end } = F..|| true {}
-   |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `bool`, found struct `std::ops::Range`
+   |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `bool`, found struct `Range`
    |
    = note: expected type `bool`
             found struct `std::ops::Range<bool>`
@@ -1812,7 +1812,7 @@ error[E0308]: mismatched types
 LL |     while let Range { start: true, end } = t..&&false {}
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^^   - this expression has type `&&bool`
    |               |
-   |               expected `bool`, found struct `std::ops::Range`
+   |               expected `bool`, found struct `Range`
    |
    = note: expected type `bool`
             found struct `std::ops::Range<_>`
@@ -1833,7 +1833,7 @@ error[E0308]: mismatched types
   --> $DIR/disallowed-positions.rs:282:11
    |
 LL |     while let Range { start: true, end } = t..&&false {}
-   |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `bool`, found struct `std::ops::Range`
+   |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `bool`, found struct `Range`
    |
    = note: expected type `bool`
             found struct `std::ops::Range<bool>`
@@ -1883,7 +1883,7 @@ error[E0308]: mismatched types
 LL |     (let Range { start: _, end: _ } = true..true || false);
    |          ^^^^^^^^^^^^^^^^^^^^^^^^^^   ---- this expression has type `bool`
    |          |
-   |          expected `bool`, found struct `std::ops::Range`
+   |          expected `bool`, found struct `Range`
    |
    = note: expected type `bool`
             found struct `std::ops::Range<_>`
diff --git a/src/test/ui/rfc-2632-const-trait-impl/issue-79450.rs b/src/test/ui/rfc-2632-const-trait-impl/issue-79450.rs
new file mode 100644 (file)
index 0000000..b604c65
--- /dev/null
@@ -0,0 +1,20 @@
+#![feature(const_fmt_arguments_new)]
+#![feature(const_trait_impl)]
+
+#[const_trait]
+trait Tr {
+    fn req(&self);
+
+    fn prov(&self) {
+        println!("lul"); //~ ERROR: cannot call non-const fn `_print` in constant functions
+        self.req();
+    }
+}
+
+struct S;
+
+impl const Tr for S {
+    fn req(&self) {}
+}
+
+fn main() {}
diff --git a/src/test/ui/rfc-2632-const-trait-impl/issue-79450.stderr b/src/test/ui/rfc-2632-const-trait-impl/issue-79450.stderr
new file mode 100644 (file)
index 0000000..082c033
--- /dev/null
@@ -0,0 +1,12 @@
+error[E0015]: cannot call non-const fn `_print` in constant functions
+  --> $DIR/issue-79450.rs:9:9
+   |
+LL |         println!("lul");
+   |         ^^^^^^^^^^^^^^^
+   |
+   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+   = note: this error originates in the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0015`.
index bbb4a93623b144b8d182c675c292b2f3a4e25511..f187d0efa8451abe60bfae1fe0f013ac6439b06d 100644 (file)
@@ -1,4 +1,4 @@
-// compile-flags: -Z simulate-remapped-rust-src-base=/rustc/xyz -Z translate-remapped-path-to-local-path=no -Z ui-testing=no
+// compile-flags: -Z simulate-remapped-rust-src-base=/rustc/FAKE_PREFIX -Z translate-remapped-path-to-local-path=no -Z ui-testing=no
 
 struct MyError;
 impl std::error::Error for MyError {}
index 04e2b46c31738f60a3719ca04722b6205bb89d48..6c7ea007ee03e4cb6fa00d649597517d10c3c8ad 100644 (file)
@@ -7,6 +7,7 @@ error[E0277]: `MyError` doesn't implement `std::fmt::Display`
   = help: the trait `std::fmt::Display` is not implemented for `MyError`
   = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead
 note: required by a bound in `std::error::Error`
+ --> $SRC_DIR/core/src/error.rs:LL:COL
 
 error[E0277]: `MyError` doesn't implement `Debug`
  --> $DIR/issue-71363.rs:4:6
@@ -17,6 +18,7 @@ error[E0277]: `MyError` doesn't implement `Debug`
   = help: the trait `Debug` is not implemented for `MyError`
   = note: add `#[derive(Debug)]` to `MyError` or manually `impl Debug for MyError`
 note: required by a bound in `std::error::Error`
+ --> $SRC_DIR/core/src/error.rs:LL:COL
 help: consider annotating `MyError` with `#[derive(Debug)]`
   |
 3 | #[derive(Debug)]
index c0d9a8634e487db79f1e17eadda101baae793f1a..b44df962a9ba76400fcbb5445d00d00e59197341 100644 (file)
@@ -6,15 +6,10 @@ LL |     foo(1 as u32 +
    |
    = help: the trait `Add<()>` is not implemented for `u32`
    = 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
+             <&'a u32 as Add<u32>>
+             <&u32 as Add<&u32>>
+             <u32 as Add<&u32>>
+             <u32 as Add>
 
 error: aborting due to previous error
 
index 2a0e9497a21faf91093b0a016a7d327c206ad1ab..15900bef7f62458493a9a04fb0ae4c7ad900fbf4 100644 (file)
@@ -120,59 +120,59 @@ hir-stats Name                Accumulated Size         Count     Item Size
 hir-stats ----------------------------------------------------------------
 hir-stats ForeignItemRef            24 ( 0.3%)             1            24
 hir-stats Lifetime                  24 ( 0.3%)             1            24
-hir-stats Mod                       32 ( 0.3%)             1            32
+hir-stats Mod                       32 ( 0.4%)             1            32
 hir-stats ExprField                 40 ( 0.4%)             1            40
 hir-stats TraitItemRef              56 ( 0.6%)             2            28
 hir-stats Local                     64 ( 0.7%)             1            64
 hir-stats Param                     64 ( 0.7%)             2            32
 hir-stats InlineAsm                 72 ( 0.8%)             1            72
 hir-stats ImplItemRef               72 ( 0.8%)             2            36
-hir-stats Body                      96 ( 1.0%)             3            32
-hir-stats FieldDef                  96 ( 1.0%)             2            48
-hir-stats Arm                       96 ( 1.0%)             2            48
-hir-stats Stmt                      96 ( 1.0%)             3            32
-hir-stats - Local                     32 ( 0.3%)             1
-hir-stats - Semi                      32 ( 0.3%)             1
-hir-stats - Expr                      32 ( 0.3%)             1
+hir-stats Body                      96 ( 1.1%)             3            32
+hir-stats FieldDef                  96 ( 1.1%)             2            48
+hir-stats Arm                       96 ( 1.1%)             2            48
+hir-stats Stmt                      96 ( 1.1%)             3            32
+hir-stats - Local                     32 ( 0.4%)             1
+hir-stats - Semi                      32 ( 0.4%)             1
+hir-stats - Expr                      32 ( 0.4%)             1
 hir-stats FnDecl                   120 ( 1.3%)             3            40
 hir-stats Attribute                128 ( 1.4%)             4            32
 hir-stats GenericArg               128 ( 1.4%)             4            32
-hir-stats - Type                      32 ( 0.3%)             1
-hir-stats - Lifetime                  96 ( 1.0%)             3
+hir-stats - Type                      32 ( 0.4%)             1
+hir-stats - Lifetime                  96 ( 1.1%)             3
 hir-stats GenericArgs              144 ( 1.6%)             3            48
 hir-stats Variant                  176 ( 1.9%)             2            88
 hir-stats GenericBound             192 ( 2.1%)             4            48
 hir-stats - Trait                    192 ( 2.1%)             4
 hir-stats WherePredicate           192 ( 2.1%)             3            64
 hir-stats - BoundPredicate           192 ( 2.1%)             3
-hir-stats Block                    288 ( 3.1%)             6            48
-hir-stats Pat                      360 ( 3.9%)             5            72
+hir-stats Block                    288 ( 3.2%)             6            48
+hir-stats Pat                      360 ( 4.0%)             5            72
 hir-stats - Wild                      72 ( 0.8%)             1
 hir-stats - Struct                    72 ( 0.8%)             1
 hir-stats - Binding                  216 ( 2.4%)             3
 hir-stats GenericParam             400 ( 4.4%)             5            80
-hir-stats Generics                 560 ( 6.1%)            10            56
-hir-stats Ty                       720 ( 7.9%)            15            48
+hir-stats Generics                 560 ( 6.2%)            10            56
+hir-stats Ty                       720 ( 8.0%)            15            48
 hir-stats - Ptr                       48 ( 0.5%)             1
 hir-stats - Rptr                      48 ( 0.5%)             1
-hir-stats - Path                     624 ( 6.8%)            13
-hir-stats Expr                     768 ( 8.4%)            12            64
+hir-stats - Path                     624 ( 6.9%)            13
+hir-stats Expr                     768 ( 8.5%)            12            64
 hir-stats - Path                      64 ( 0.7%)             1
 hir-stats - Struct                    64 ( 0.7%)             1
 hir-stats - Match                     64 ( 0.7%)             1
 hir-stats - InlineAsm                 64 ( 0.7%)             1
 hir-stats - Lit                      128 ( 1.4%)             2
 hir-stats - Block                    384 ( 4.2%)             6
-hir-stats Item                     960 (10.5%)            12            80
+hir-stats Item                     880 ( 9.7%)            11            80
 hir-stats - Trait                     80 ( 0.9%)             1
 hir-stats - Enum                      80 ( 0.9%)             1
 hir-stats - ExternCrate               80 ( 0.9%)             1
 hir-stats - ForeignMod                80 ( 0.9%)             1
 hir-stats - Impl                      80 ( 0.9%)             1
-hir-stats - Fn                       160 ( 1.7%)             2
-hir-stats - Use                      400 ( 4.4%)             5
-hir-stats Path                   1_280 (14.0%)            32            40
-hir-stats PathSegment            1_920 (20.9%)            40            48
+hir-stats - Fn                       160 ( 1.8%)             2
+hir-stats - Use                      320 ( 3.5%)             4
+hir-stats Path                   1_240 (13.7%)            31            40
+hir-stats PathSegment            1_920 (21.2%)            40            48
 hir-stats ----------------------------------------------------------------
-hir-stats Total                  9_168
+hir-stats Total                  9_048
 hir-stats
index 5ae1b727dc772f44054ae2a90b00433479216d24..7f48f55fec93803d3e89f002ee57963edcfde507 100644 (file)
@@ -28,6 +28,7 @@ fn foo() {}
     //~^ ERROR functions are not allowed in enum definitions
     //~| HELP unlike in C++, Java, and C#, functions are declared in `impl` blocks
     //~| HELP see https://doc.rust-lang.org/book/ch05-03-method-syntax.html for more information
+    //~| HELP enum variants can be `Variant`, `Variant = <integer>`, `Variant(Type, ..., TypeN)` or `Variant { fields: Types }`
 }
 
 fn main() {}
index 472365c6ed739288a7c1378ee095dc8be11b4ef0..439c86ec22b0eb9178e39fd2c5569be225a94a3b 100644 (file)
@@ -33,6 +33,7 @@ LL |     fn foo() {}
    |
    = help: unlike in C++, Java, and C#, functions are declared in `impl` blocks
    = help: see https://doc.rust-lang.org/book/ch05-03-method-syntax.html for more information
+   = help: enum variants can be `Variant`, `Variant = <integer>`, `Variant(Type, ..., TypeN)` or `Variant { fields: Types }`
 
 error: aborting due to 3 previous errors
 
index f4fd655e698b08171f3d6375d673c6d098f9ab5d..9b751d1b66c54d79547acb96e05a76068f2079e1 100644 (file)
@@ -18,7 +18,7 @@ error[E0308]: mismatched types
   --> $DIR/struct-record-suggestion.rs:23:20
    |
 LL |     let q = B { b: 1..Default::default() };
-   |                    ^^^^^^^^^^^^^^^^^^^^^ expected `u32`, found struct `std::ops::Range`
+   |                    ^^^^^^^^^^^^^^^^^^^^^ expected `u32`, found struct `Range`
    |
    = note: expected type `u32`
             found struct `std::ops::Range<{integer}>`
diff --git a/src/test/ui/structs/unresolved-struct-with-fru.rs b/src/test/ui/structs/unresolved-struct-with-fru.rs
new file mode 100644 (file)
index 0000000..c9fdca4
--- /dev/null
@@ -0,0 +1,12 @@
+struct S {
+    a: u32,
+}
+
+fn main() {
+    let s1 = S { a: 1 };
+
+    let _ = || {
+        let s2 = Oops { a: 2, ..s1 };
+        //~^ ERROR cannot find struct, variant or union type `Oops` in this scope
+    };
+}
diff --git a/src/test/ui/structs/unresolved-struct-with-fru.stderr b/src/test/ui/structs/unresolved-struct-with-fru.stderr
new file mode 100644 (file)
index 0000000..a5796a2
--- /dev/null
@@ -0,0 +1,9 @@
+error[E0422]: cannot find struct, variant or union type `Oops` in this scope
+  --> $DIR/unresolved-struct-with-fru.rs:9:18
+   |
+LL |         let s2 = Oops { a: 2, ..s1 };
+   |                  ^^^^ not found in this scope
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0422`.
diff --git a/src/test/ui/suggestions/assoc-const-as-fn.rs b/src/test/ui/suggestions/assoc-const-as-fn.rs
new file mode 100644 (file)
index 0000000..4b4595d
--- /dev/null
@@ -0,0 +1,18 @@
+unsafe fn pointer(v: usize, w: u32) {}
+
+pub trait UniformScalar {}
+impl UniformScalar for u32 {}
+
+pub trait GlUniformScalar: UniformScalar {
+    const FACTORY: unsafe fn(usize, Self) -> ();
+}
+impl GlUniformScalar for u32 {
+    const FACTORY: unsafe fn(usize, Self) -> () = pointer;
+}
+
+pub fn foo<T: UniformScalar>(value: T) {
+    <T as GlUniformScalar>::FACTORY(1, value);
+    //~^ ERROR the trait bound `T: GlUniformScalar` is not satisfied
+}
+
+fn main() {}
diff --git a/src/test/ui/suggestions/assoc-const-as-fn.stderr b/src/test/ui/suggestions/assoc-const-as-fn.stderr
new file mode 100644 (file)
index 0000000..3b6e947
--- /dev/null
@@ -0,0 +1,16 @@
+error[E0277]: the trait bound `T: GlUniformScalar` is not satisfied
+  --> $DIR/assoc-const-as-fn.rs:14:40
+   |
+LL |     <T as GlUniformScalar>::FACTORY(1, value);
+   |     -------------------------------    ^^^^^ the trait `GlUniformScalar` is not implemented for `T`
+   |     |
+   |     required by a bound introduced by this call
+   |
+help: consider further restricting this bound
+   |
+LL | pub fn foo<T: UniformScalar + GlUniformScalar>(value: T) {
+   |                             +++++++++++++++++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
index d53715937f7d841ed3be7007bfe747c91700d84f..4cb595c32c0611ebad6ca6950c6eb56ebac0f969 100644 (file)
@@ -80,7 +80,7 @@ note: required by a bound in `std::mem::size_of`
   --> $SRC_DIR/core/src/mem/mod.rs:LL:COL
    |
 LL | pub const fn size_of<T>() -> usize {
-   |                      ^ required by this bound in `std::mem::size_of`
+   |                      ^ required by this bound in `size_of`
 help: consider further restricting `Self`
    |
 LL | trait Foo<T>: Sized {
@@ -96,7 +96,7 @@ note: required by a bound in `std::mem::size_of`
   --> $SRC_DIR/core/src/mem/mod.rs:LL:COL
    |
 LL | pub const fn size_of<T>() -> usize {
-   |                      ^ required by this bound in `std::mem::size_of`
+   |                      ^ required by this bound in `size_of`
 help: consider further restricting `Self`
    |
 LL | trait Bar: std::fmt::Display + Sized {
@@ -112,7 +112,7 @@ note: required by a bound in `std::mem::size_of`
   --> $SRC_DIR/core/src/mem/mod.rs:LL:COL
    |
 LL | pub const fn size_of<T>() -> usize {
-   |                      ^ required by this bound in `std::mem::size_of`
+   |                      ^ required by this bound in `size_of`
 help: consider further restricting `Self`
    |
 LL | trait Baz: Sized where Self: std::fmt::Display {
@@ -128,7 +128,7 @@ note: required by a bound in `std::mem::size_of`
   --> $SRC_DIR/core/src/mem/mod.rs:LL:COL
    |
 LL | pub const fn size_of<T>() -> usize {
-   |                      ^ required by this bound in `std::mem::size_of`
+   |                      ^ required by this bound in `size_of`
 help: consider further restricting `Self`
    |
 LL | trait Qux<T>: Sized where Self: std::fmt::Display {
@@ -144,7 +144,7 @@ note: required by a bound in `std::mem::size_of`
   --> $SRC_DIR/core/src/mem/mod.rs:LL:COL
    |
 LL | pub const fn size_of<T>() -> usize {
-   |                      ^ required by this bound in `std::mem::size_of`
+   |                      ^ required by this bound in `size_of`
 help: consider further restricting `Self`
    |
 LL | trait Bat<T>: std::fmt::Display + Sized {
index e8250c9fa5ff49971a87e91409bdb89320602937..98b88b4fb9202cc7d5ccbe50e6f81e3278dad298 100644 (file)
@@ -20,12 +20,6 @@ help: there is a crate or module with a similar name
 LL | use bar::bar;
    |     ~~~
 
-error[E0433]: failed to resolve: use of undeclared crate or module `bar`
-  --> $DIR/crate-or-module-typo.rs:6:20
-   |
-LL |     pub fn bar() { bar::baz(); }
-   |                    ^^^ use of undeclared crate or module `bar`
-
 error[E0433]: failed to resolve: use of undeclared crate or module `st`
   --> $DIR/crate-or-module-typo.rs:14:10
    |
@@ -37,6 +31,12 @@ help: there is a crate or module with a similar name
 LL |     bar: std::cell::Cell<bool>
    |          ~~~
 
+error[E0433]: failed to resolve: use of undeclared crate or module `bar`
+  --> $DIR/crate-or-module-typo.rs:6:20
+   |
+LL |     pub fn bar() { bar::baz(); }
+   |                    ^^^ use of undeclared crate or module `bar`
+
 error: aborting due to 4 previous errors
 
 Some errors have detailed explanations: E0432, E0433.
index 4e21d36014c9045afc27508826558583a308670e..bc6342004f4db638b4cdb89015a2127ce0cb7bab 100644 (file)
@@ -2,7 +2,10 @@ error[E0308]: mismatched types
   --> $DIR/dont-suggest-try_into-in-macros.rs:2:5
    |
 LL |     assert_eq!(10u64, 10usize);
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `u64`, found `usize`
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |     |
+   |     expected `u64`, found `usize`
+   |     expected because this is `u64`
    |
    = note: this error originates in the macro `assert_eq` (in Nightly builds, run with -Z macro-backtrace for more info)
 
index 04e0511d788ed160de56b1f6f05689d2527d315d..0d9543e0b8fa22d61ae4280b051aabe571f7aeef 100644 (file)
@@ -2,13 +2,7 @@ error[E0599]: no method named `MAX` found for type `u32` in the current scope
   --> $DIR/dont-suggest-ufcs-for-const.rs:2:11
    |
 LL |     1_u32.MAX();
-   |     ------^^^--
-   |     |     |
-   |     |     this is an associated function, not a method
-   |     help: use associated function syntax instead: `u32::MAX()`
-   |
-   = note: found the following associated functions; to be used as methods, functions must have a `self` parameter
-   = note: the candidate is defined in an impl for the type `u32`
+   |           ^^^ method not found in `u32`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/suggestions/issue-105226.rs b/src/test/ui/suggestions/issue-105226.rs
new file mode 100644 (file)
index 0000000..f123dbf
--- /dev/null
@@ -0,0 +1,22 @@
+use std::fmt;
+
+struct S {
+}
+
+impl S {
+    fn hello<P>(&self, val: &P) where P: fmt::Display; {
+        //~^ ERROR non-item in item list
+        //~| ERROR associated function in `impl` without body
+        println!("val: {}", val);
+    }
+}
+
+impl S {
+    fn hello_empty<P>(&self, val: &P) where P: fmt::Display;
+    //~^ ERROR associated function in `impl` without body
+}
+
+fn main() {
+    let s = S{};
+    s.hello(&32);
+}
diff --git a/src/test/ui/suggestions/issue-105226.stderr b/src/test/ui/suggestions/issue-105226.stderr
new file mode 100644 (file)
index 0000000..f16a809
--- /dev/null
@@ -0,0 +1,31 @@
+error: non-item in item list
+  --> $DIR/issue-105226.rs:7:56
+   |
+LL | impl S {
+   |        - item list starts here
+LL |     fn hello<P>(&self, val: &P) where P: fmt::Display; {
+   |                                                      - ^ non-item starts here
+   |                                                      |
+   |                                                      help: consider removing this semicolon
+...
+LL | }
+   | - item list ends here
+
+error: associated function in `impl` without body
+  --> $DIR/issue-105226.rs:7:5
+   |
+LL |     fn hello<P>(&self, val: &P) where P: fmt::Display; {
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
+   |                                                      |
+   |                                                      help: provide a definition for the function: `{ <body> }`
+
+error: associated function in `impl` without body
+  --> $DIR/issue-105226.rs:15:5
+   |
+LL |     fn hello_empty<P>(&self, val: &P) where P: fmt::Display;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
+   |                                                            |
+   |                                                            help: provide a definition for the function: `{ <body> }`
+
+error: aborting due to 3 previous errors
+
index 57a934b83420cc0da80c5d74b191c946cafb1d0c..4050c7be82a0af369c459b9cc5f36217cc153746 100644 (file)
@@ -2,7 +2,9 @@ error[E0308]: mismatched types
   --> $DIR/option-to-bool.rs:4:16
    |
 LL |     if true && x {}
-   |                ^ expected `bool`, found enum `Option`
+   |        ----    ^ expected `bool`, found enum `Option`
+   |        |
+   |        expected because this is `bool`
    |
    = note: expected type `bool`
               found enum `Option<i32>`
index 9d0573ca2554d536b610bcb5b57e84fc43684e45..1b7289b229b5d488fba8bb5385ca18fd4042dd0f 100644 (file)
@@ -14,4 +14,19 @@ fn use_foo(x: Foo) -> i32 {
     return foo;
 }
 
+// issue #105028, suggest removing the field only for shorthand
+fn use_match(x: Foo) {
+    match x {
+        Foo { foo: unused, .. } => { //~ WARNING unused variable
+                                     //~| help: if this is intentional, prefix it with an underscore
+        }
+    }
+
+    match x {
+        Foo { foo, .. } => { //~ WARNING unused variable
+                             //~| help: try removing the field
+        }
+    }
+}
+
 fn main() {}
index 448a2c3d2ec27a8be9663a575f51ded43a2cf9b4..7a6013d4a6eab978f2900f75b3f50a1f9e2c5ed6 100644 (file)
@@ -8,5 +8,19 @@ LL |     let Foo { foo, bar, .. } = x;
    |
    = note: `#[warn(unused_variables)]` on by default
 
-warning: 1 warning emitted
+warning: unused variable: `unused`
+  --> $DIR/try-removing-the-field.rs:20:20
+   |
+LL |         Foo { foo: unused, .. } => {
+   |                    ^^^^^^ help: if this is intentional, prefix it with an underscore: `_unused`
+
+warning: unused variable: `foo`
+  --> $DIR/try-removing-the-field.rs:26:15
+   |
+LL |         Foo { foo, .. } => {
+   |               ^^^-
+   |               |
+   |               help: try removing the field
+
+warning: 3 warnings emitted
 
index 773f1392ae7655827c2e619bf95beefdcefb48a8..34eaa8322c8701e70f451c34a510a4567055d18d 100644 (file)
@@ -2,7 +2,7 @@ error[E0308]: mismatched types
   --> $DIR/unnecessary_dot_for_floating_point_literal.rs:2:18
    |
 LL |     let _: f64 = 0..10;
-   |            ---   ^^^^^ expected `f64`, found struct `std::ops::Range`
+   |            ---   ^^^^^ expected `f64`, found struct `Range`
    |            |
    |            expected due to this
    |
@@ -47,7 +47,7 @@ error[E0308]: mismatched types
   --> $DIR/unnecessary_dot_for_floating_point_literal.rs:5:18
    |
 LL |     let _: f64 = std::ops::Range { start: 0, end: 1 };
-   |            ---   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `f64`, found struct `std::ops::Range`
+   |            ---   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `f64`, found struct `Range`
    |            |
    |            expected due to this
    |
diff --git a/src/test/ui/trait-bounds/impl-bound-with-references-error.rs b/src/test/ui/trait-bounds/impl-bound-with-references-error.rs
new file mode 100644 (file)
index 0000000..e5d0a1a
--- /dev/null
@@ -0,0 +1,20 @@
+// Regression test for #105138.
+// This test ensures that the compiler does not add note
+// for implementation of trait whose inner type is erroneous.
+
+pub enum LabelText {
+    Plain,
+}
+
+impl<T> From<T> for LabelText
+//~^ ERROR conflicting implementations of trait `From<LabelText>` for type `LabelText` [E0119]
+where
+    T: Into<Cow<'static, str>>,
+    //~^ ERROR cannot find type `Cow` in this scope [E0412]
+{
+    fn from(text: T) -> Self {
+        LabelText::Plain(text.into())
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/trait-bounds/impl-bound-with-references-error.stderr b/src/test/ui/trait-bounds/impl-bound-with-references-error.stderr
new file mode 100644 (file)
index 0000000..95fd6bd
--- /dev/null
@@ -0,0 +1,24 @@
+error[E0412]: cannot find type `Cow` in this scope
+  --> $DIR/impl-bound-with-references-error.rs:12:13
+   |
+LL |     T: Into<Cow<'static, str>>,
+   |             ^^^ not found in this scope
+   |
+help: consider importing this enum
+   |
+LL | use std::borrow::Cow;
+   |
+
+error[E0119]: conflicting implementations of trait `From<LabelText>` for type `LabelText`
+  --> $DIR/impl-bound-with-references-error.rs:9:1
+   |
+LL | impl<T> From<T> for LabelText
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: conflicting implementation in crate `core`:
+           - impl<T> From<T> for T;
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0119, E0412.
+For more information about an error, try `rustc --explain E0119`.
diff --git a/src/test/ui/trait-bounds/impl-missing-where-clause-lifetimes-from-trait.rs b/src/test/ui/trait-bounds/impl-missing-where-clause-lifetimes-from-trait.rs
new file mode 100644 (file)
index 0000000..dcdbd02
--- /dev/null
@@ -0,0 +1,38 @@
+trait Trait<T> {
+    fn foo<'a, K>(self, _: T, _: K) where T: 'a, K: 'a;
+}
+
+impl Trait<()> for () {
+    fn foo<'a, K>(self, _: (), _: K) where { //~ ERROR E0195
+        todo!();
+    }
+}
+
+struct State;
+
+trait Foo<T> {
+    fn foo<'a>(&self, state: &'a State) -> &'a T
+    where
+        T: 'a;
+}
+
+impl<F, T> Foo<T> for F
+where
+    F: Fn(&State) -> &T,
+{
+    fn foo<'a>(&self, state: &'a State) -> &'a T { //~ ERROR E0195
+        self(state)
+    }
+}
+
+trait Bar {
+    fn foo<'a>(&'a self) {}
+}
+
+impl Bar for () {
+    fn foo<'a: 'a>(&'a self) {} //~ ERROR E0195
+}
+
+fn main() {
+    ().foo((), ());
+}
diff --git a/src/test/ui/trait-bounds/impl-missing-where-clause-lifetimes-from-trait.stderr b/src/test/ui/trait-bounds/impl-missing-where-clause-lifetimes-from-trait.stderr
new file mode 100644 (file)
index 0000000..e26cb22
--- /dev/null
@@ -0,0 +1,36 @@
+error[E0195]: lifetime parameters or bounds on method `foo` do not match the trait declaration
+  --> $DIR/impl-missing-where-clause-lifetimes-from-trait.rs:6:11
+   |
+LL |     fn foo<'a, K>(self, _: T, _: K) where T: 'a, K: 'a;
+   |           -------                            --     -- this bound might be missing in the impl
+   |           |                                  |
+   |           |                                  this bound might be missing in the impl
+   |           lifetimes in impl do not match this method in trait
+...
+LL |     fn foo<'a, K>(self, _: (), _: K) where {
+   |           ^^^^^^^ lifetimes do not match method in trait
+
+error[E0195]: lifetime parameters or bounds on method `foo` do not match the trait declaration
+  --> $DIR/impl-missing-where-clause-lifetimes-from-trait.rs:23:11
+   |
+LL |     fn foo<'a>(&self, state: &'a State) -> &'a T
+   |           ---- lifetimes in impl do not match this method in trait
+LL |     where
+LL |         T: 'a;
+   |            -- this bound might be missing in the impl
+...
+LL |     fn foo<'a>(&self, state: &'a State) -> &'a T {
+   |           ^^^^ lifetimes do not match method in trait
+
+error[E0195]: lifetime parameters or bounds on method `foo` do not match the trait declaration
+  --> $DIR/impl-missing-where-clause-lifetimes-from-trait.rs:33:11
+   |
+LL |     fn foo<'a>(&'a self) {}
+   |           ---- lifetimes in impl do not match this method in trait
+...
+LL |     fn foo<'a: 'a>(&'a self) {}
+   |           ^^^^^^^^ lifetimes do not match method in trait
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0195`.
index 56e8fcff0fce507f3bd96dcc969373f7b95e74f2..8db5fa615c08d30a107a5251399fa58d825f2752 100644 (file)
@@ -1,15 +1,15 @@
 #![feature(rustc_attrs)]
 
 #[rustc_must_implement_one_of(a, a)]
-//~^ Functions names are duplicated
+//~^ functions names are duplicated
 trait Trait {
     fn a() {}
 }
 
 #[rustc_must_implement_one_of(b, a, a, c, b, c)]
-//~^ Functions names are duplicated
-//~| Functions names are duplicated
-//~| Functions names are duplicated
+//~^ functions names are duplicated
+//~| functions names are duplicated
+//~| functions names are duplicated
 trait Trait1 {
     fn a() {}
     fn b() {}
index 777beba618277f50d9aa4f1314956f7de4b41838..cd1476a6eb81b4e039bafe293c1cba61d7647cb0 100644 (file)
@@ -1,34 +1,34 @@
-error: Functions names are duplicated
+error: functions names are duplicated
   --> $DIR/rustc_must_implement_one_of_duplicates.rs:3:31
    |
 LL | #[rustc_must_implement_one_of(a, a)]
    |                               ^  ^
    |
-   = note: All `#[rustc_must_implement_one_of]` arguments must be unique
+   = note: all `#[rustc_must_implement_one_of]` arguments must be unique
 
-error: Functions names are duplicated
+error: functions names are duplicated
   --> $DIR/rustc_must_implement_one_of_duplicates.rs:9:34
    |
 LL | #[rustc_must_implement_one_of(b, a, a, c, b, c)]
    |                                  ^  ^
    |
-   = note: All `#[rustc_must_implement_one_of]` arguments must be unique
+   = note: all `#[rustc_must_implement_one_of]` arguments must be unique
 
-error: Functions names are duplicated
+error: functions names are duplicated
   --> $DIR/rustc_must_implement_one_of_duplicates.rs:9:31
    |
 LL | #[rustc_must_implement_one_of(b, a, a, c, b, c)]
    |                               ^           ^
    |
-   = note: All `#[rustc_must_implement_one_of]` arguments must be unique
+   = note: all `#[rustc_must_implement_one_of]` arguments must be unique
 
-error: Functions names are duplicated
+error: functions names are duplicated
   --> $DIR/rustc_must_implement_one_of_duplicates.rs:9:40
    |
 LL | #[rustc_must_implement_one_of(b, a, a, c, b, c)]
    |                                        ^     ^
    |
-   = note: All `#[rustc_must_implement_one_of]` arguments must be unique
+   = note: all `#[rustc_must_implement_one_of]` arguments must be unique
 
 error: aborting due to 4 previous errors
 
index 1f896da94db57c279aefcae77bcef77009587a66..b1b91966c8d8883ab6cfc2aaa95a652f79648136 100644 (file)
@@ -1,12 +1,12 @@
 #![feature(rustc_attrs)]
 
 #[rustc_must_implement_one_of(a, b)]
-//~^ Function not found in this trait
-//~| Function not found in this trait
+//~^ function not found in this trait
+//~| function not found in this trait
 trait Tr0 {}
 
 #[rustc_must_implement_one_of(a, b)]
-//~^ Function not found in this trait
+//~^ function not found in this trait
 trait Tr1 {
     fn a() {}
 }
@@ -23,16 +23,16 @@ trait Tr3 {}
 
 #[rustc_must_implement_one_of(A, B)]
 trait Tr4 {
-    const A: u8 = 1; //~ Not a function
+    const A: u8 = 1; //~ not a function
 
-    type B; //~ Not a function
+    type B; //~ not a function
 }
 
 #[rustc_must_implement_one_of(a, b)]
 trait Tr5 {
-    fn a(); //~ This function doesn't have a default implementation
+    fn a(); //~ function doesn't have a default implementation
 
-    fn b(); //~ This function doesn't have a default implementation
+    fn b(); //~ function doesn't have a default implementation
 }
 
 #[rustc_must_implement_one_of(abc, xyz)]
index 869184f0d1a69fc3f28f5ccd186116077158f634..38e692521ca23508dd310e2935de0a393bb061a3 100644 (file)
@@ -22,19 +22,19 @@ LL |
 LL | struct Struct {}
    | ---------------- not a trait
 
-error: Function not found in this trait
+error: function not found in this trait
   --> $DIR/rustc_must_implement_one_of_misuse.rs:3:31
    |
 LL | #[rustc_must_implement_one_of(a, b)]
    |                               ^
 
-error: Function not found in this trait
+error: function not found in this trait
   --> $DIR/rustc_must_implement_one_of_misuse.rs:3:34
    |
 LL | #[rustc_must_implement_one_of(a, b)]
    |                                  ^
 
-error: Function not found in this trait
+error: function not found in this trait
   --> $DIR/rustc_must_implement_one_of_misuse.rs:8:34
    |
 LL | #[rustc_must_implement_one_of(a, b)]
@@ -46,7 +46,7 @@ error: the `#[rustc_must_implement_one_of]` attribute must be used with at least
 LL | #[rustc_must_implement_one_of(a)]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: Not a function
+error: not a function
   --> $DIR/rustc_must_implement_one_of_misuse.rs:26:5
    |
 LL |     const A: u8 = 1;
@@ -57,9 +57,9 @@ note: required by this annotation
    |
 LL | #[rustc_must_implement_one_of(A, B)]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   = note: All `#[rustc_must_implement_one_of]` arguments must be associated function names
+   = note: all `#[rustc_must_implement_one_of]` arguments must be associated function names
 
-error: Not a function
+error: not a function
   --> $DIR/rustc_must_implement_one_of_misuse.rs:28:5
    |
 LL |     type B;
@@ -70,9 +70,9 @@ note: required by this annotation
    |
 LL | #[rustc_must_implement_one_of(A, B)]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   = note: All `#[rustc_must_implement_one_of]` arguments must be associated function names
+   = note: all `#[rustc_must_implement_one_of]` arguments must be associated function names
 
-error: This function doesn't have a default implementation
+error: function doesn't have a default implementation
   --> $DIR/rustc_must_implement_one_of_misuse.rs:33:5
    |
 LL |     fn a();
@@ -84,7 +84,7 @@ note: required by this annotation
 LL | #[rustc_must_implement_one_of(a, b)]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: This function doesn't have a default implementation
+error: function doesn't have a default implementation
   --> $DIR/rustc_must_implement_one_of_misuse.rs:35:5
    |
 LL |     fn b();
index cf2e4edf9f0a9081e113ee2fec115b9c74ba6d07..08f7bbbf0eafe7fb4309cc0f4ba7c4e24dab3321 100644 (file)
@@ -7,10 +7,7 @@ LL | struct Foo<'a, T> {
 LL |     bar: &'a mut T
    |     ^^^^^^^^^^^^^^ the trait `Clone` is not implemented for `&mut T`
    |
-   = help: the following other types implement trait `Clone`:
-             &T
-             *const T
-             *mut T
+   = help: the trait `Clone` is implemented for `&T`
    = note: `Clone` is implemented for `&T`, but not for `&mut T`
    = note: this error originates in the derive macro `Clone` (in Nightly builds, run with -Z macro-backtrace for more info)
 
index a74d2524996a10d4d9f85c9ed166f1733264c3fe..1f18c5daf66e3dd2c0944da6fe3f8becd61e2552 100644 (file)
@@ -17,7 +17,7 @@ error[E0275]: overflow evaluating the requirement `(): Sized`
    = help: consider increasing the recursion limit by adding a `#![recursion_limit = "512"]` attribute to your crate (`issue_91949_hangs_on_recursion`)
    = note: required for `std::iter::Empty<()>` to implement `Iterator`
    = note: 171 redundant requirements hidden
-   = note: required for `IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<..., ...>>, ...>>` to implement `Iterator`
+   = note: required for `IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<..., ...>>, ...>>, ...>>` to implement `Iterator`
    = note: the full type name has been written to '$TEST_BUILD_DIR/traits/issue-91949-hangs-on-recursion/issue-91949-hangs-on-recursion.long-type-hash.txt'
 
 error: aborting due to previous error; 1 warning emitted
diff --git a/src/test/ui/traits/object/issue-44454-1.rs b/src/test/ui/traits/object/issue-44454-1.rs
new file mode 100644 (file)
index 0000000..bbaf318
--- /dev/null
@@ -0,0 +1,22 @@
+// Taken from https://github.com/rust-lang/rust/issues/44454#issue-256435333
+
+trait Animal<X>: 'static {}
+
+fn foo<Y, X>()
+where
+    Y: Animal<X> + ?Sized,
+{
+    // `Y` implements `Animal<X>` so `Y` is 'static.
+    baz::<Y>()
+}
+
+fn bar<'a>(_arg: &'a i32) {
+    foo::<dyn Animal<&'a i32>, &'a i32>() //~ ERROR: lifetime may not live long enough
+}
+
+fn baz<T: 'static + ?Sized>() {}
+
+fn main() {
+    let a = 5;
+    bar(&a);
+}
diff --git a/src/test/ui/traits/object/issue-44454-1.stderr b/src/test/ui/traits/object/issue-44454-1.stderr
new file mode 100644 (file)
index 0000000..859487f
--- /dev/null
@@ -0,0 +1,10 @@
+error: lifetime may not live long enough
+  --> $DIR/issue-44454-1.rs:14:5
+   |
+LL | fn bar<'a>(_arg: &'a i32) {
+   |        -- lifetime `'a` defined here
+LL |     foo::<dyn Animal<&'a i32>, &'a i32>()
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'a` must outlive `'static`
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/traits/object/issue-44454-2.rs b/src/test/ui/traits/object/issue-44454-2.rs
new file mode 100644 (file)
index 0000000..f5178bc
--- /dev/null
@@ -0,0 +1,22 @@
+// Taken from https://github.com/rust-lang/rust/issues/44454#issuecomment-1175925928
+
+trait Trait<ARG: 'static>: 'static {
+    type Assoc: AsRef<str>;
+}
+
+fn hr<T: ?Sized, ARG>(x: T::Assoc) -> Box<dyn AsRef<str> + 'static>
+where
+    T: Trait<ARG>
+{
+    Box::new(x)
+}
+
+fn extend_lt<'a>(x: &'a str) -> Box<dyn AsRef<str> + 'static> {
+    type DynTrait = dyn for<'a> Trait<&'a str, Assoc = &'a str>;
+    hr::<DynTrait, _>(x) //~ ERROR: borrowed data escapes outside of function
+}
+
+fn main() {
+    let extended = extend_lt(&String::from("hello"));
+    println!("{}", extended.as_ref().as_ref());
+}
diff --git a/src/test/ui/traits/object/issue-44454-2.stderr b/src/test/ui/traits/object/issue-44454-2.stderr
new file mode 100644 (file)
index 0000000..7f57476
--- /dev/null
@@ -0,0 +1,17 @@
+error[E0521]: borrowed data escapes outside of function
+  --> $DIR/issue-44454-2.rs:16:5
+   |
+LL | fn extend_lt<'a>(x: &'a str) -> Box<dyn AsRef<str> + 'static> {
+   |              --  - `x` is a reference that is only valid in the function body
+   |              |
+   |              lifetime `'a` defined here
+LL |     type DynTrait = dyn for<'a> Trait<&'a str, Assoc = &'a str>;
+LL |     hr::<DynTrait, _>(x)
+   |     ^^^^^^^^^^^^^^^^^^^^
+   |     |
+   |     `x` escapes the function body here
+   |     argument requires that `'a` must outlive `'static`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0521`.
diff --git a/src/test/ui/traits/object/issue-44454-3.rs b/src/test/ui/traits/object/issue-44454-3.rs
new file mode 100644 (file)
index 0000000..bff7270
--- /dev/null
@@ -0,0 +1,33 @@
+// Taken from https://github.com/rust-lang/rust/issues/44454#issuecomment-1332781290
+
+use std::any::Any;
+
+trait Animal<X>: 'static {}
+
+trait Projector {
+    type Foo;
+}
+
+impl<X> Projector for dyn Animal<X> {
+    type Foo = X;
+}
+
+fn make_static<'a, T>(t: &'a T) -> &'static T {
+    let x: <dyn Animal<&'a T> as Projector>::Foo = t;
+    let any = generic::<dyn Animal<&'a T>, &'a T>(x);
+    //~^ ERROR: lifetime may not live long enough
+    any.downcast_ref::<&'static T>().unwrap()
+}
+
+fn generic<T: Projector + Animal<U> + ?Sized, U>(x: <T as Projector>::Foo) -> Box<dyn Any> {
+    make_static_any(x)
+}
+
+fn make_static_any<U: 'static>(u: U) -> Box<dyn Any> {
+    Box::new(u)
+}
+
+fn main() {
+    let a = make_static(&"salut".to_string());
+    println!("{}", *a);
+}
diff --git a/src/test/ui/traits/object/issue-44454-3.stderr b/src/test/ui/traits/object/issue-44454-3.stderr
new file mode 100644 (file)
index 0000000..294684d
--- /dev/null
@@ -0,0 +1,11 @@
+error: lifetime may not live long enough
+  --> $DIR/issue-44454-3.rs:17:15
+   |
+LL | fn make_static<'a, T>(t: &'a T) -> &'static T {
+   |                -- lifetime `'a` defined here
+LL |     let x: <dyn Animal<&'a T> as Projector>::Foo = t;
+LL |     let any = generic::<dyn Animal<&'a T>, &'a T>(x);
+   |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'a` must outlive `'static`
+
+error: aborting due to previous error
+
index 747e2477b9cf14193c2c806ec2d87c09136e8f32..9765fbd47ff465daf1afaf57991872a4cb6ed83e 100644 (file)
@@ -11,7 +11,7 @@ note: required by a bound in `std::mem::size_of`
   --> $SRC_DIR/core/src/mem/mod.rs:LL:COL
    |
 LL | pub const fn size_of<T>() -> usize {
-   |                      ^ required by this bound in `std::mem::size_of`
+   |                      ^ required by this bound in `size_of`
 help: consider removing the `?Sized` bound to make the type parameter `Sized`
    |
 LL - fn check<T: Iterator, U: ?Sized>() {
@@ -36,7 +36,7 @@ note: required by a bound in `std::mem::size_of`
   --> $SRC_DIR/core/src/mem/mod.rs:LL:COL
    |
 LL | pub const fn size_of<T>() -> usize {
-   |                      ^ required by this bound in `std::mem::size_of`
+   |                      ^ required by this bound in `size_of`
 help: consider removing the `?Sized` bound to make the type parameter `Sized`
    |
 LL - fn check<T: Iterator, U: ?Sized>() {
@@ -82,7 +82,7 @@ note: required by a bound in `std::mem::size_of`
   --> $SRC_DIR/core/src/mem/mod.rs:LL:COL
    |
 LL | pub const fn size_of<T>() -> usize {
-   |                      ^ required by this bound in `std::mem::size_of`
+   |                      ^ required by this bound in `size_of`
 
 error[E0277]: the size for values of type `[&U]` cannot be known at compilation time
   --> $DIR/suggest-where-clause.rs:31:20
@@ -95,7 +95,7 @@ note: required by a bound in `std::mem::size_of`
   --> $SRC_DIR/core/src/mem/mod.rs:LL:COL
    |
 LL | pub const fn size_of<T>() -> usize {
-   |                      ^ required by this bound in `std::mem::size_of`
+   |                      ^ required by this bound in `size_of`
 
 error: aborting due to 7 previous errors
 
index 419a86bf33bb4444b2c3582efc8c1247a86f33d9..a49630adb9538b83d0ad7755fe577768b6cb674f 100644 (file)
@@ -8,15 +8,8 @@ LL |     Ok(Err(123_i32)?)
    |
    = note: the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait
    = help: the following other types implement trait `From<T>`:
-             <f32 as From<i16>>
-             <f32 as From<i8>>
-             <f32 as From<u16>>
-             <f32 as From<u8>>
-             <f64 as From<f32>>
-             <f64 as From<i16>>
-             <f64 as From<i32>>
-             <f64 as From<i8>>
-           and 68 others
+             <u8 as From<NonZeroU8>>
+             <u8 as From<bool>>
    = note: required for `Result<u64, u8>` to implement `FromResidual<Result<Infallible, i32>>`
 
 error[E0277]: the `?` operator can only be used on `Result`s, not `Option`s, in a function that returns `Result`
index 2b505d30730a3e2079a01e08368d12d0540e4329..c2cf70687fd20bfca203f12e14e50fef82f11d56 100644 (file)
@@ -7,16 +7,7 @@ LL |     42_i32
    |     ------ return type was inferred to be `i32` here
    |
    = help: the trait `PartialEq<Foo>` is not implemented for `i32`
-   = help: the following other types implement trait `PartialEq<Rhs>`:
-             f32
-             f64
-             i128
-             i16
-             i32
-             i64
-             i8
-             isize
-           and 6 others
+   = help: the trait `PartialEq` is implemented for `i32`
 
 error: aborting due to previous error
 
index 27880f792f462e6c279454d7f2806692aaf91b76..98c762e3d38207e29ed442005cff266dfe9a09c9 100644 (file)
@@ -7,16 +7,7 @@ LL |     i
    |     - return type was inferred to be `&i32` here
    |
    = help: the trait `PartialEq<Bar<'b, 'static>>` is not implemented for `&i32`
-   = help: the following other types implement trait `PartialEq<Rhs>`:
-             f32
-             f64
-             i128
-             i16
-             i32
-             i64
-             i8
-             isize
-           and 6 others
+   = help: the trait `PartialEq` is implemented for `i32`
 
 error[E0277]: can't compare `&i32` with `Foo<'static, 'b>`
   --> $DIR/self-referential-4.rs:11:31
@@ -27,16 +18,7 @@ LL |     i
    |     - return type was inferred to be `&i32` here
    |
    = help: the trait `PartialEq<Foo<'static, 'b>>` is not implemented for `&i32`
-   = help: the following other types implement trait `PartialEq<Rhs>`:
-             f32
-             f64
-             i128
-             i16
-             i32
-             i64
-             i8
-             isize
-           and 6 others
+   = help: the trait `PartialEq` is implemented for `i32`
 
 error[E0277]: can't compare `&i32` with `Moo<'static, 'a>`
   --> $DIR/self-referential-4.rs:17:31
@@ -47,16 +29,7 @@ LL |     i
    |     - return type was inferred to be `&i32` here
    |
    = help: the trait `PartialEq<Moo<'static, 'a>>` is not implemented for `&i32`
-   = help: the following other types implement trait `PartialEq<Rhs>`:
-             f32
-             f64
-             i128
-             i16
-             i32
-             i64
-             i8
-             isize
-           and 6 others
+   = help: the trait `PartialEq` is implemented for `i32`
 
 error: aborting due to 3 previous errors
 
index 97d510f6830af2ca621d5b191667081ad3af50d2..aff489d70e389f60e85f6e03583c92e3cd9d80f4 100644 (file)
@@ -8,16 +8,7 @@ LL |     i
    |     - return type was inferred to be `&i32` here
    |
    = help: the trait `PartialEq<Bar<'b, 'a>>` is not implemented for `&i32`
-   = help: the following other types implement trait `PartialEq<Rhs>`:
-             f32
-             f64
-             i128
-             i16
-             i32
-             i64
-             i8
-             isize
-           and 6 others
+   = help: the trait `PartialEq` is implemented for `i32`
 
 error[E0277]: can't compare `&i32` with `(i32, &i32)`
   --> $DIR/self-referential.rs:12:31
@@ -29,16 +20,7 @@ LL |     (42, i)
    |     ------- return type was inferred to be `(i32, &i32)` here
    |
    = help: the trait `PartialEq<(i32, &i32)>` is not implemented for `&i32`
-   = help: the following other types implement trait `PartialEq<Rhs>`:
-             f32
-             f64
-             i128
-             i16
-             i32
-             i64
-             i8
-             isize
-           and 6 others
+   = help: the trait `PartialEq` is implemented for `i32`
 
 error[E0277]: can't compare `&i32` with `(i32, Moo<'b, 'a>::{opaque#0})`
   --> $DIR/self-referential.rs:19:31
@@ -50,16 +32,7 @@ LL |     (42, i)
    |     ------- return type was inferred to be `(i32, &i32)` here
    |
    = help: the trait `PartialEq<(i32, Moo<'b, 'a>::{opaque#0})>` is not implemented for `&i32`
-   = help: the following other types implement trait `PartialEq<Rhs>`:
-             f32
-             f64
-             i128
-             i16
-             i32
-             i64
-             i8
-             isize
-           and 6 others
+   = help: the trait `PartialEq` is implemented for `i32`
 
 error: aborting due to 3 previous errors
 
index a8139063db1d8aea857cdd2354cd1ac65d4250ab..fc85ec933155621972a0d939cfa0e981f1741dc1 100644 (file)
@@ -55,7 +55,7 @@ error[E0308]: mismatched types
   --> $DIR/type-ascription-precedence.rs:53:5
    |
 LL |     (S .. S): S;
-   |     ^^^^^^^^ expected struct `S`, found struct `std::ops::Range`
+   |     ^^^^^^^^ expected struct `S`, found struct `Range`
    |
    = note: expected struct `S`
               found struct `std::ops::Range<S>`
index d583fc2131a747dd046a268aa362a1b2fcd90edd..08316cdcd35ec21c619c873b5677da12868ef859 100644 (file)
@@ -4,10 +4,10 @@
 
 fn main() {
     let arr = &[1u8, 2, 3];
-    let ref x = arr: &[u8]; //~ ERROR mismatched types
-    let ref mut x = arr: &[u8]; //~ ERROR mismatched types
-    match arr: &[u8] { //~ ERROR mismatched types
+    let ref x = type_ascribe!(arr, &[u8]);      //~ ERROR mismatched types
+    let ref mut x = type_ascribe!(arr, &[u8]);  //~ ERROR mismatched types
+    match type_ascribe!(arr, &[u8]) {           //~ ERROR mismatched types
         ref x => {}
     }
-    let _len = (arr: &[u8]).len(); //~ ERROR mismatched types
+    let _len = type_ascribe!(arr, &[u8]).len();              //~ ERROR mismatched types
 }
index 6ed940823af1af43d00654b28fde7ac3dc7e1c5b..522d5b2e375553319b37c8bd3873e54e4896849e 100644 (file)
@@ -1,35 +1,35 @@
 error[E0308]: mismatched types
-  --> $DIR/type-ascription-soundness.rs:7:17
+  --> $DIR/type-ascription-soundness.rs:7:31
    |
-LL |     let ref x = arr: &[u8];
-   |                 ^^^ expected slice `[u8]`, found array `[u8; 3]`
+LL |     let ref x = type_ascribe!(arr, &[u8]);
+   |                               ^^^ expected slice `[u8]`, found array `[u8; 3]`
    |
    = note: expected reference `&[u8]`
               found reference `&[u8; 3]`
 
 error[E0308]: mismatched types
-  --> $DIR/type-ascription-soundness.rs:8:21
+  --> $DIR/type-ascription-soundness.rs:8:35
    |
-LL |     let ref mut x = arr: &[u8];
-   |                     ^^^ expected slice `[u8]`, found array `[u8; 3]`
+LL |     let ref mut x = type_ascribe!(arr, &[u8]);
+   |                                   ^^^ expected slice `[u8]`, found array `[u8; 3]`
    |
    = note: expected reference `&[u8]`
               found reference `&[u8; 3]`
 
 error[E0308]: mismatched types
-  --> $DIR/type-ascription-soundness.rs:9:11
+  --> $DIR/type-ascription-soundness.rs:9:25
    |
-LL |     match arr: &[u8] {
-   |           ^^^ expected slice `[u8]`, found array `[u8; 3]`
+LL |     match type_ascribe!(arr, &[u8]) {
+   |                         ^^^ expected slice `[u8]`, found array `[u8; 3]`
    |
    = note: expected reference `&[u8]`
               found reference `&[u8; 3]`
 
 error[E0308]: mismatched types
-  --> $DIR/type-ascription-soundness.rs:12:17
+  --> $DIR/type-ascription-soundness.rs:12:30
    |
-LL |     let _len = (arr: &[u8]).len();
-   |                 ^^^ expected slice `[u8]`, found array `[u8; 3]`
+LL |     let _len = type_ascribe!(arr, &[u8]).len();
+   |                              ^^^ expected slice `[u8]`, found array `[u8; 3]`
    |
    = note: expected reference `&[u8]`
               found reference `&[u8; 3]`
index 7adb074428ce97cb025e3a2b651ece681a20249d..e4a4c89d057f2701d5494c6360c290ed938cce0a 100644 (file)
@@ -8,32 +8,32 @@
 
 use std::mem;
 
-const C1: u8 = 10: u8;
-const C2: [u8; 1: usize] = [1];
+const C1: u8 = type_ascribe!(10, u8);
+const C2: [u8; type_ascribe!(1, usize)] = [1];
 
 struct S {
     a: u8
 }
 
 fn main() {
-    assert_eq!(C1.into(): i32, 10);
+    assert_eq!(type_ascribe!(C1.into(), i32), 10);
     assert_eq!(C2[0], 1);
 
-    let s = S { a: 10: u8 };
+    let s = S { a: type_ascribe!(10, u8) };
     let arr = &[1u8, 2, 3];
 
-    let mut v = arr.iter().cloned().collect(): Vec<_>;
+    let mut v = type_ascribe!(arr.iter().cloned().collect(), Vec<_>);
     v.push(4);
     assert_eq!(v, [1, 2, 3, 4]);
 
-    let a = 1: u8;
-    let b = a.into(): u16;
-    assert_eq!(v[a.into(): usize], 2);
+    let a = type_ascribe!(1, u8);
+    let b = type_ascribe!(a.into(), u16);
+    assert_eq!(v[type_ascribe!(a.into(), usize)], 2);
     assert_eq!(mem::size_of_val(&a), 1);
     assert_eq!(mem::size_of_val(&b), 2);
-    assert_eq!(b, 1: u16);
+    assert_eq!(b, type_ascribe!(1, u16));
 
     let mut v = Vec::new();
-    v: Vec<u8> = vec![1, 2, 3]; // Place expression type ascription
+    type_ascribe!(v, Vec<u8>) = vec![1, 2, 3]; // Place expression type ascription
     assert_eq!(v, [1u8, 2, 3]);
 }
index cf77c057d46d4b5babce2b4b9e23d96f786982f6..9ba63ffe9c93f4de1b45f28f6dde3d0937926d27 100644 (file)
@@ -66,15 +66,10 @@ LL | trait ProjectionPred<T:Iterator = IntoIter<i32>> where T::Item : Add<u8> {}
    |
    = help: the trait `Add<u8>` 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
+             <&i32 as Add<&i32>>
+             <i32 as Add<&i32>>
+             <i32 as Add>
 
 error: aborting due to 7 previous errors
 
index 8ab08e25e30920213a4c8e03cc669b11adcce23b..9f4558adab150708696dc1aba163bd6cdbacca3d 100644 (file)
@@ -68,7 +68,9 @@ error[E0308]: mismatched types
   --> $DIR/assignment-in-if.rs:44:18
    |
 LL |     if x == x && x = x && x == x {
-   |                  ^ expected `bool`, found `usize`
+   |        ------    ^ expected `bool`, found `usize`
+   |        |
+   |        expected because this is `bool`
 
 error[E0308]: mismatched types
   --> $DIR/assignment-in-if.rs:44:22
@@ -91,7 +93,9 @@ error[E0308]: mismatched types
   --> $DIR/assignment-in-if.rs:51:28
    |
 LL |     if x == x && x == x && x = x {
-   |                            ^ expected `bool`, found `usize`
+   |        ----------------    ^ expected `bool`, found `usize`
+   |        |
+   |        expected because this is `bool`
 
 error[E0308]: mismatched types
   --> $DIR/assignment-in-if.rs:51:8
index 4e73e10a3014382815b80cb672e1b359c1a694e5..7529f25bd8e4b318e12f6b05a521323c4a21dfd0 100644 (file)
@@ -6,7 +6,9 @@ LL | trait BrokenAdd: Copy + Add<Output=Self> {
 LL |     fn broken_add<T>(&self, rhs: T) -> Self {
    |                   - found type parameter
 LL |         *self + rhs
-   |                 ^^^ expected type parameter `Self`, found type parameter `T`
+   |         -----   ^^^ expected type parameter `Self`, found type parameter `T`
+   |         |
+   |         expected because this is `Self`
    |
    = note: expected type parameter `Self`
               found type parameter `T`
diff --git a/src/test/ui/typeck/issue-104582.rs b/src/test/ui/typeck/issue-104582.rs
new file mode 100644 (file)
index 0000000..104669d
--- /dev/null
@@ -0,0 +1,5 @@
+fn main(){
+    let my_var: String(String?);
+    //~^ ERROR: invalid `?` in type
+    //~| ERROR: parenthesized type parameters may only be used with a `Fn` trait
+}
diff --git a/src/test/ui/typeck/issue-104582.stderr b/src/test/ui/typeck/issue-104582.stderr
new file mode 100644 (file)
index 0000000..61b6b23
--- /dev/null
@@ -0,0 +1,25 @@
+error: invalid `?` in type
+  --> $DIR/issue-104582.rs:2:30
+   |
+LL |     let my_var: String(String?);
+   |                              ^ `?` is only allowed on expressions, not types
+   |
+help: if you meant to express that the type might not contain a value, use the `Option` wrapper type
+   |
+LL |     let my_var: String(Option<String>);
+   |                        +++++++      ~
+
+error[E0214]: parenthesized type parameters may only be used with a `Fn` trait
+  --> $DIR/issue-104582.rs:2:17
+   |
+LL |     let my_var: String(String?);
+   |                 ^^^^^^^^^^^^^^^ only `Fn` traits may use parentheses
+   |
+help: use angle brackets instead
+   |
+LL |     let my_var: String<String?>;
+   |                       ~       ~
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0214`.
index 657bda5f62b3f2605ec329981c7f442a10ea130f..876ac2c67ef3f34cf19718cff61a7a2bb65dc5a7 100644 (file)
@@ -5,7 +5,7 @@ LL |     fn nodes<'a, I: Iterator<Item=&'a N>>(&self) -> I
    |                  - this type parameter              - expected `I` because of return type
 ...
 LL |         self.iter()
-   |         ^^^^^^^^^^^ expected type parameter `I`, found struct `std::slice::Iter`
+   |         ^^^^^^^^^^^ expected type parameter `I`, found struct `Iter`
    |
    = note: expected type parameter `I`
                       found struct `std::slice::Iter<'_, N>`
index 9658288ac8b28df9abe531e7d20220a8bcd7708a..6976be71135c2dfe92f08724249dfc56c9493f11 100644 (file)
@@ -21,15 +21,10 @@ LL |     a = c + b * 5;
    |
    = help: the trait `Add<u16>` is not implemented for `usize`
    = 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
+             <&'a usize as Add<usize>>
+             <&usize as Add<&usize>>
+             <usize as Add<&usize>>
+             <usize as Add>
 
 error: aborting due to 3 previous errors
 
index f5a37e9cb86f8c89d723ea5b8f2b324758923d1a..4e39cfab5b439b1f5656c16e5bdea02264303505 100644 (file)
@@ -1,5 +1,7 @@
+#![feature(type_ascription)]
+
 fn main() {
-    0: u8<e<5>=e>
+    type_ascribe!(0, u8<e<5>=e>)
     //~^ ERROR: cannot find type `e` in this scope [E0412]
     //~| ERROR: associated type bindings are not allowed here [E0229]
     //~| ERROR: mismatched types [E0308]
index aac00b9b6a941eaae5e6ad9ff8f74c684cb2784c..72acd9c673b63a4a9e0c64a566da3f2d337cc34d 100644 (file)
@@ -1,25 +1,22 @@
 error[E0412]: cannot find type `e` in this scope
-  --> $DIR/issue-91267.rs:2:16
+  --> $DIR/issue-91267.rs:4:30
    |
-LL |     0: u8<e<5>=e>
-   |                ^
-   |                |
-   |                not found in this scope
-   |                help: maybe you meant to write an assignment here: `let e`
+LL |     type_ascribe!(0, u8<e<5>=e>)
+   |                              ^ not found in this scope
 
 error[E0229]: associated type bindings are not allowed here
-  --> $DIR/issue-91267.rs:2:11
+  --> $DIR/issue-91267.rs:4:25
    |
-LL |     0: u8<e<5>=e>
-   |           ^^^^^^ associated type not allowed here
+LL |     type_ascribe!(0, u8<e<5>=e>)
+   |                         ^^^^^^ associated type not allowed here
 
 error[E0308]: mismatched types
-  --> $DIR/issue-91267.rs:2:5
+  --> $DIR/issue-91267.rs:4:5
    |
 LL | fn main() {
    |           - expected `()` because of default return type
-LL |     0: u8<e<5>=e>
-   |     ^^^^^^^^^^^^^ expected `()`, found `u8`
+LL |     type_ascribe!(0, u8<e<5>=e>)
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `()`, found `u8`
 
 error: aborting due to 3 previous errors
 
diff --git a/src/test/ui/typeck/path-to-method-sugg-unresolved-expr.rs b/src/test/ui/typeck/path-to-method-sugg-unresolved-expr.rs
new file mode 100644 (file)
index 0000000..fb56b39
--- /dev/null
@@ -0,0 +1,4 @@
+fn main() {
+    let page_size = page_size::get();
+    //~^ ERROR failed to resolve: use of undeclared crate or module `page_size`
+}
diff --git a/src/test/ui/typeck/path-to-method-sugg-unresolved-expr.stderr b/src/test/ui/typeck/path-to-method-sugg-unresolved-expr.stderr
new file mode 100644 (file)
index 0000000..b01e30b
--- /dev/null
@@ -0,0 +1,9 @@
+error[E0433]: failed to resolve: use of undeclared crate or module `page_size`
+  --> $DIR/path-to-method-sugg-unresolved-expr.rs:2:21
+   |
+LL |     let page_size = page_size::get();
+   |                     ^^^^^^^^^ use of undeclared crate or module `page_size`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0433`.
index eaab6ff3d9a0419227d6ad01307049dbebcc021a..ed56e1cf957f5c719c0b3ea01f37448ae2b2a354 100644 (file)
@@ -8,15 +8,10 @@ LL |     <i32 as Add<u32>>::add(1, 2);
    |
    = 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
+             <&i32 as Add<&i32>>
+             <i32 as Add<&i32>>
+             <i32 as Add>
 
 error[E0308]: mismatched types
   --> $DIR/ufcs-qpath-self-mismatch.rs:7:28
@@ -62,15 +57,10 @@ LL |     <i32 as Add<u32>>::add(1, 2);
    |
    = 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
+             <&i32 as Add<&i32>>
+             <i32 as Add<&i32>>
+             <i32 as Add>
 
 error: aborting due to 4 previous errors
 
diff --git a/src/test/ui/wf/hir-wf-canonicalized.rs b/src/test/ui/wf/hir-wf-canonicalized.rs
new file mode 100644 (file)
index 0000000..bdb8440
--- /dev/null
@@ -0,0 +1,18 @@
+// incremental
+
+trait Foo {
+    type V;
+}
+
+trait Callback<T: Foo>: Fn(&Bar<'_, T>, &T::V) {}
+
+struct Bar<'a, T> {
+    callback: Box<dyn Callback<dyn Callback<Bar<'a, T>>>>,
+    //~^ ERROR the trait bound `Bar<'a, T>: Foo` is not satisfied
+    //~| ERROR the trait bound `(dyn Callback<Bar<'a, T>, for<'b, 'c, 'd> Output = ()> + 'static): Foo` is not satisfied
+    //~| ERROR the size for values of type `(dyn Callback<Bar<'a, T>, for<'b, 'c, 'd> Output = ()> + 'static)` cannot be known at compilation time
+}
+
+impl<T: Foo> Bar<'_, Bar<'_, T>> {}
+
+fn main() {}
diff --git a/src/test/ui/wf/hir-wf-canonicalized.stderr b/src/test/ui/wf/hir-wf-canonicalized.stderr
new file mode 100644 (file)
index 0000000..9fd0f9c
--- /dev/null
@@ -0,0 +1,32 @@
+error[E0277]: the trait bound `Bar<'a, T>: Foo` is not satisfied
+  --> $DIR/hir-wf-canonicalized.rs:10:15
+   |
+LL |     callback: Box<dyn Callback<dyn Callback<Bar<'a, T>>>>,
+   |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Foo` is not implemented for `Bar<'a, T>`
+
+error[E0277]: the trait bound `(dyn Callback<Bar<'a, T>, for<'b, 'c, 'd> Output = ()> + 'static): Foo` is not satisfied
+  --> $DIR/hir-wf-canonicalized.rs:10:15
+   |
+LL |     callback: Box<dyn Callback<dyn Callback<Bar<'a, T>>>>,
+   |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Foo` is not implemented for `(dyn Callback<Bar<'a, T>, for<'b, 'c, 'd> Output = ()> + 'static)`
+
+error[E0277]: the size for values of type `(dyn Callback<Bar<'a, T>, for<'b, 'c, 'd> Output = ()> + 'static)` cannot be known at compilation time
+  --> $DIR/hir-wf-canonicalized.rs:10:15
+   |
+LL |     callback: Box<dyn Callback<dyn Callback<Bar<'a, T>>>>,
+   |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `(dyn Callback<Bar<'a, T>, for<'b, 'c, 'd> Output = ()> + 'static)`
+note: required by a bound in `Bar`
+  --> $DIR/hir-wf-canonicalized.rs:9:16
+   |
+LL | struct Bar<'a, T> {
+   |                ^ required by this bound in `Bar`
+help: consider relaxing the implicit `Sized` restriction
+   |
+LL | struct Bar<'a, T: ?Sized> {
+   |                 ++++++++
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
index 9f8896f01ee06f90e776c07c1ccbfdfa8a496216..8338f61b22a756941d048eaa59d04c33263e8b99 100644 (file)
@@ -38,7 +38,9 @@ error[E0308]: mismatched types
   --> $DIR/wrong-mul-method-signature.rs:63:45
    |
 LL |     let x: Vec2 = Vec2 { x: 1.0, y: 2.0 } * 2.0; // trait had reversed order
-   |                                             ^^^ expected struct `Vec2`, found floating-point number
+   |                   -----------------------   ^^^ expected struct `Vec2`, found floating-point number
+   |                   |
+   |                   expected because this is `Vec2`
 
 error[E0308]: mismatched types
   --> $DIR/wrong-mul-method-signature.rs:63:19
index e027c4b5d25af2119b1956fac42863b9b3242744..70898e522116f6c23971e2a554b2dc85fd4c84cd 160000 (submodule)
@@ -1 +1 @@
-Subproject commit e027c4b5d25af2119b1956fac42863b9b3242744
+Subproject commit 70898e522116f6c23971e2a554b2dc85fd4c84cd
index 6f1f73c1fd2fe385e06badeb46983a8860864c44..23912bb3ed6b16aea9a4ce27ad1cd5a1a2f50661 100644 (file)
@@ -4188,6 +4188,7 @@ Released 2018-09-13
 [`misaligned_transmute`]: https://rust-lang.github.io/rust-clippy/master/index.html#misaligned_transmute
 [`mismatched_target_os`]: https://rust-lang.github.io/rust-clippy/master/index.html#mismatched_target_os
 [`mismatching_type_param_order`]: https://rust-lang.github.io/rust-clippy/master/index.html#mismatching_type_param_order
+[`misnamed_getters`]: https://rust-lang.github.io/rust-clippy/master/index.html#misnamed_getters
 [`misrefactored_assign_op`]: https://rust-lang.github.io/rust-clippy/master/index.html#misrefactored_assign_op
 [`missing_const_for_fn`]: https://rust-lang.github.io/rust-clippy/master/index.html#missing_const_for_fn
 [`missing_docs_in_private_items`]: https://rust-lang.github.io/rust-clippy/master/index.html#missing_docs_in_private_items
@@ -4450,6 +4451,7 @@ Released 2018-09-13
 [`unnecessary_mut_passed`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_mut_passed
 [`unnecessary_operation`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_operation
 [`unnecessary_owned_empty_strings`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_owned_empty_strings
+[`unnecessary_safety_comment`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_safety_comment
 [`unnecessary_safety_doc`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_safety_doc
 [`unnecessary_self_imports`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_self_imports
 [`unnecessary_sort_by`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_sort_by
index f74de7de42b8b0d20d5c59b2d71cace4f776c7e6..81254ba8b8b8f7faf163e4be75172a847cfceb4a 100644 (file)
@@ -197,8 +197,8 @@ disallowed-names = ["toto", "tata", "titi"]
 cognitive-complexity-threshold = 30
 ```
 
-See the [list of lints](https://rust-lang.github.io/rust-clippy/master/index.html) for more information about which
-lints can be configured and the meaning of the variables.
+See the [list of configurable lints](https://rust-lang.github.io/rust-clippy/master/index.html#Configuration),
+the lint descriptions contain the names and meanings of these configuration variables.
 
 > **Note**
 >
@@ -224,7 +224,7 @@ in the `Cargo.toml` can be used.
 rust-version = "1.30"
 ```
 
-The MSRV can also be specified as an inner attribute, like below.
+The MSRV can also be specified as an attribute, like below.
 
 ```rust
 #![feature(custom_inner_attributes)]
index 0b945faf9b78effe2d1dbd0fc5d6a269c87c50a2..1f0b8db28a152e19c48ccd93f46285036a18e9ef 100644 (file)
@@ -21,3 +21,4 @@
         - [The Clippy Book](development/infrastructure/book.md)
     - [Proposals](development/proposals/README.md)
         - [Roadmap 2021](development/proposals/roadmap-2021.md)
+        - [Syntax Tree Patterns](development/proposals/syntax-tree-patterns.md)
index 77f1d2e8797a36c2200c5563e0b05085bc3c4b9e..430ff8b739ae861785c528b749728a199f6ee72c 100644 (file)
@@ -11,8 +11,8 @@ disallowed-names = ["toto", "tata", "titi"]
 cognitive-complexity-threshold = 30
 ```
 
-See the [list of lints](https://rust-lang.github.io/rust-clippy/master/index.html) for more information about which
-lints can be configured and the meaning of the variables.
+See the [list of configurable lints](https://rust-lang.github.io/rust-clippy/master/index.html#Configuration),
+the lint descriptions contain the names and meanings of these configuration variables.
 
 To deactivate the "for further information visit *lint-link*" message you can define the `CLIPPY_DISABLE_DOCS_LINKS`
 environment variable.
@@ -72,7 +72,7 @@ minimum supported Rust version (MSRV) in the clippy configuration file.
 msrv = "1.30.0"
 ```
 
-The MSRV can also be specified as an inner attribute, like below.
+The MSRV can also be specified as an attribute, like below.
 
 ```rust
 #![feature(custom_inner_attributes)]
index 3c3f368a529b15755ca687375d1becf2a635a8a0..8b4eee8c9d94d3b3f6ddaaa72507a59de8149d70 100644 (file)
@@ -443,27 +443,27 @@ value is passed to the constructor in `clippy_lints/lib.rs`.
 
 ```rust
 pub struct ManualStrip {
-    msrv: Option<RustcVersion>,
+    msrv: Msrv,
 }
 
 impl ManualStrip {
     #[must_use]
-    pub fn new(msrv: Option<RustcVersion>) -> Self {
+    pub fn new(msrv: Msrv) -> Self {
         Self { msrv }
     }
 }
 ```
 
 The project's MSRV can then be matched against the feature MSRV in the LintPass
-using the `meets_msrv` utility function.
+using the `Msrv::meets` method.
 
 ``` rust
-if !meets_msrv(self.msrv, msrvs::STR_STRIP_PREFIX) {
+if !self.msrv.meets(msrvs::STR_STRIP_PREFIX) {
     return;
 }
 ```
 
-The project's MSRV can also be specified as an inner attribute, which overrides
+The project's MSRV can also be specified as an attribute, which overrides
 the value from `clippy.toml`. This can be accounted for using the
 `extract_msrv_attr!(LintContext)` macro and passing
 `LateContext`/`EarlyContext`.
@@ -483,19 +483,15 @@ have a case for the version below the MSRV and one with the same contents but
 for the MSRV version itself.
 
 ```rust
-#![feature(custom_inner_attributes)]
-
 ...
 
+#[clippy::msrv = "1.44"]
 fn msrv_1_44() {
-    #![clippy::msrv = "1.44"]
-
     /* something that would trigger the lint */
 }
 
+#[clippy::msrv = "1.45"]
 fn msrv_1_45() {
-    #![clippy::msrv = "1.45"]
-
     /* something that would trigger the lint */
 }
 ```
diff --git a/src/tools/clippy/book/src/development/proposals/syntax-tree-patterns.md b/src/tools/clippy/book/src/development/proposals/syntax-tree-patterns.md
new file mode 100644 (file)
index 0000000..c5587c4
--- /dev/null
@@ -0,0 +1,986 @@
+- Feature Name: syntax-tree-patterns
+- Start Date: 2019-03-12
+- RFC PR: [#3875](https://github.com/rust-lang/rust-clippy/pull/3875)
+
+# Summary
+
+Introduce a domain-specific language (similar to regular expressions) that
+allows to describe lints using *syntax tree patterns*.
+
+
+# Motivation
+
+Finding parts of a syntax tree (AST, HIR, ...) that have certain properties
+(e.g. "*an if that has a block as its condition*") is a major task when writing
+lints. For non-trivial lints, it often requires nested pattern matching of AST /
+HIR nodes. For example, testing that an expression is a boolean literal requires
+the following checks:
+
+```rust
+if let ast::ExprKind::Lit(lit) = &expr.node {
+    if let ast::LitKind::Bool(_) = &lit.node {
+        ...
+    }
+}
+```
+
+Writing this kind of matching code quickly becomes a complex task and the
+resulting code is often hard to comprehend. The code below shows a simplified
+version of the pattern matching required by the `collapsible_if` lint:
+
+```rust
+// simplified version of the collapsible_if lint
+if let ast::ExprKind::If(check, then, None) = &expr.node {
+    if then.stmts.len() == 1 {
+        if let ast::StmtKind::Expr(inner) | ast::StmtKind::Semi(inner) = &then.stmts[0].node {
+            if let ast::ExprKind::If(check_inner, content, None) = &inner.node {
+                ...
+            }
+        }
+    }
+}
+```
+
+The `if_chain` macro can improve readability by flattening the nested if
+statements, but the resulting code is still quite hard to read:
+
+```rust
+// simplified version of the collapsible_if lint
+if_chain! {
+    if let ast::ExprKind::If(check, then, None) = &expr.node;
+    if then.stmts.len() == 1;
+    if let ast::StmtKind::Expr(inner) | ast::StmtKind::Semi(inner) = &then.stmts[0].node;
+    if let ast::ExprKind::If(check_inner, content, None) = &inner.node;
+    then {
+        ...
+    }
+}
+```
+
+The code above matches if expressions that contain only another if expression
+(where both ifs don't have an else branch). While it's easy to explain what the
+lint does, it's hard to see that from looking at the code samples above.
+
+Following the motivation above, the first goal this RFC is to **simplify writing
+and reading lints**.
+
+The second part of the motivation is clippy's dependence on unstable
+compiler-internal data structures. Clippy lints are currently written against
+the compiler's AST / HIR which means that even small changes in these data
+structures might break a lot of lints. The second goal of this RFC is to **make
+lints independant of the compiler's AST / HIR data structures**.
+
+# Approach
+
+A lot of complexity in writing lints currently seems to come from having to
+manually implement the matching logic (see code samples above). It's an
+imparative style that describes *how* to match a syntax tree node instead of
+specifying *what* should be matched against declaratively. In other areas, it's
+common to use declarative patterns to describe desired information and let the
+implementation do the actual matching. A well-known example of this approach are
+[regular expressions](https://en.wikipedia.org/wiki/Regular_expression). Instead
+of writing code that detects certain character sequences, one can describe a
+search pattern using a domain-specific language and search for matches using
+that pattern. The advantage of using a declarative domain-specific language is
+that its limited domain (e.g. matching character sequences in the case of
+regular expressions) allows to express entities in that domain in a very natural
+and expressive way.
+
+While regular expressions are very useful when searching for patterns in flat
+character sequences, they cannot easily be applied to hierarchical data
+structures like syntax trees. This RFC therefore proposes a pattern matching
+system that is inspired by regular expressions and designed for hierarchical
+syntax trees.
+
+# Guide-level explanation
+
+This proposal adds a `pattern!` macro that can be used to specify a syntax tree
+pattern to search for. A simple pattern is shown below:
+
+```rust
+pattern!{
+    my_pattern: Expr =
+        Lit(Bool(false))
+}
+```
+
+This macro call defines a pattern named `my_pattern` that can be matched against
+an `Expr` syntax tree node. The actual pattern (`Lit(Bool(false))` in this case)
+defines which syntax trees should match the pattern. This pattern matches
+expressions that are boolean literals with value `false`.
+
+The pattern can then be used to implement lints in the following way:
+
+```rust
+...
+
+impl EarlyLintPass for MyAwesomeLint {
+    fn check_expr(&mut self, cx: &EarlyContext, expr: &syntax::ast::Expr) {
+
+        if my_pattern(expr).is_some() {
+            cx.span_lint(
+                MY_AWESOME_LINT,
+                expr.span,
+                "This is a match for a simple pattern. Well done!",
+            );
+        }
+
+    }
+}
+```
+
+The `pattern!` macro call expands to a function `my_pattern` that expects a
+syntax tree expression as its argument and returns an `Option` that indicates
+whether the pattern matched.
+
+> Note: The result type is explained in more detail in [a later
+> section](#the-result-type). For now, it's enough to know that the result is
+> `Some` if the pattern matched and `None` otherwise.
+
+## Pattern syntax
+
+The following examples demonstate the pattern syntax:
+
+
+#### Any (`_`)
+
+The simplest pattern is the any pattern. It matches anything and is therefore
+similar to regex's `*`.
+
+```rust
+pattern!{
+    // matches any expression
+    my_pattern: Expr =
+        _
+}
+```
+
+#### Node (`<node-name>(<args>)`)
+
+Nodes are used to match a specific variant of an AST node. A node has a name and
+a number of arguments that depends on the node type. For example, the `Lit` node
+has a single argument that describes the type of the literal. As another
+example, the `If` node has three arguments describing the if's condition, then
+block and else block.
+
+```rust
+pattern!{
+    // matches any expression that is a literal
+    my_pattern: Expr =
+        Lit(_)
+}
+
+pattern!{
+    // matches any expression that is a boolean literal
+    my_pattern: Expr =
+        Lit(Bool(_))
+}
+
+pattern!{
+    // matches if expressions that have a boolean literal in their condition
+    // Note: The `_?` syntax here means that the else branch is optional and can be anything.
+    //       This is discussed in more detail in the section `Repetition`.
+    my_pattern: Expr =
+        If( Lit(Bool(_)) , _, _?)
+}
+```
+
+
+#### Literal (`<lit>`)
+
+A pattern can also contain Rust literals. These literals match themselves.
+
+```rust
+pattern!{
+    // matches the boolean literal false
+    my_pattern: Expr =
+        Lit(Bool(false))
+}
+
+pattern!{
+    // matches the character literal 'x'
+    my_pattern: Expr =
+        Lit(Char('x'))
+}
+```
+
+#### Alternations (`a | b`)
+
+```rust
+pattern!{
+    // matches if the literal is a boolean or integer literal
+    my_pattern: Lit =
+        Bool(_) | Int(_)
+}
+
+pattern!{
+    // matches if the expression is a char literal with value 'x' or 'y'
+    my_pattern: Expr =
+        Lit( Char('x' | 'y') )
+}
+```
+
+#### Empty (`()`)
+
+The empty pattern represents an empty sequence or the `None` variant of an
+optional.
+
+```rust
+pattern!{
+    // matches if the expression is an empty array
+    my_pattern: Expr =
+        Array( () )
+}
+
+pattern!{
+    // matches if expressions that don't have an else clause
+    my_pattern: Expr =
+        If(_, _, ())
+}
+```
+
+#### Sequence (`<a> <b>`)
+
+```rust
+pattern!{
+    // matches the array [true, false]
+    my_pattern: Expr =
+        Array( Lit(Bool(true)) Lit(Bool(false)) )
+}
+```
+
+#### Repetition (`<a>*`, `<a>+`, `<a>?`, `<a>{n}`, `<a>{n,m}`, `<a>{n,}`)
+
+Elements may be repeated. The syntax for specifying repetitions is identical to
+[regex's syntax](https://docs.rs/regex/1.1.2/regex/#repetitions).
+
+```rust
+pattern!{
+    // matches arrays that contain 2 'x's as their last or second-last elements
+    // Examples:
+    //     ['x', 'x']                         match
+    //     ['x', 'x', 'y']                    match
+    //     ['a', 'b', 'c', 'x', 'x', 'y']     match
+    //     ['x', 'x', 'y', 'z']               no match
+    my_pattern: Expr =
+        Array( _* Lit(Char('x')){2} _? )
+}
+
+pattern!{
+    // matches if expressions that **may or may not** have an else block
+    // Attn: `If(_, _, _)` matches only ifs that **have** an else block
+    //
+    //              | if with else block | if witout else block
+    // If(_, _, _)  |       match        |       no match
+    // If(_, _, _?) |       match        |        match
+    // If(_, _, ()) |      no match      |        match
+    my_pattern: Expr =
+        If(_, _, _?)
+}
+```
+
+#### Named submatch (`<a>#<name>`)
+
+```rust
+pattern!{
+    // matches character literals and gives the literal the name foo
+    my_pattern: Expr =
+        Lit(Char(_)#foo)
+}
+
+pattern!{
+    // matches character literals and gives the char the name bar
+    my_pattern: Expr =
+        Lit(Char(_#bar))
+}
+
+pattern!{
+    // matches character literals and gives the expression the name baz
+    my_pattern: Expr =
+        Lit(Char(_))#baz
+}
+```
+
+The reason for using named submatches is described in the section [The result
+type](#the-result-type).
+
+### Summary
+
+The following table gives an summary of the pattern syntax:
+
+| Syntax                  | Concept          | Examples                                   |
+|-------------------------|------------------|--------------------------------------------|
+|`_`                      | Any              | `_`                                        |
+|`<node-name>(<args>)`    | Node             | `Lit(Bool(true))`, `If(_, _, _)`           |
+|`<lit>`                  | Literal          | `'x'`, `false`, `101`                      |
+|`<a> \| <b>`             | Alternation      | `Char(_) \| Bool(_)`                       |
+|`()`                     | Empty            | `Array( () )`                              |
+|`<a> <b>`                | Sequence         | `Tuple( Lit(Bool(_)) Lit(Int(_)) Lit(_) )` |
+|`<a>*` <br> `<a>+` <br> `<a>?` <br> `<a>{n}` <br> `<a>{n,m}` <br> `<a>{n,}` | Repetition <br> <br> <br> <br> <br><br> | `Array( _* )`, <br> `Block( Semi(_)+ )`, <br> `If(_, _, Block(_)?)`, <br> `Array( Lit(_){10} )`, <br> `Lit(_){5,10}`, <br> `Lit(Bool(_)){10,}` |
+|`<a>#<name>`             | Named submatch   | `Lit(Int(_))#foo` `Lit(Int(_#bar))`        |
+
+
+## The result type
+
+A lot of lints require checks that go beyond what the pattern syntax described
+above can express. For example, a lint might want to check whether a node was
+created as part of a macro expansion or whether there's no comment above a node.
+Another example would be a lint that wants to match two nodes that have the same
+value (as needed by lints like `almost_swapped`). Instead of allowing users to
+write these checks into the pattern directly (which might make patterns hard to
+read), the proposed solution allows users to assign names to parts of a pattern
+expression. When matching a pattern against a syntax tree node, the return value
+will contain references to all nodes that were matched by these named
+subpatterns. This is similar to capture groups in regular expressions.
+
+For example, given the following pattern
+
+```rust
+pattern!{
+    // matches character literals
+    my_pattern: Expr =
+        Lit(Char(_#val_inner)#val)#val_outer
+}
+```
+
+one could get references to the nodes that matched the subpatterns in the
+following way:
+
+```rust
+...
+fn check_expr(expr: &syntax::ast::Expr) {
+    if let Some(result) = my_pattern(expr) {
+        result.val_inner  // type: &char
+        result.val        // type: &syntax::ast::Lit
+        result.val_outer  // type: &syntax::ast::Expr
+    }
+}
+```
+
+The types in the `result` struct depend on the pattern. For example, the
+following pattern
+
+```rust
+pattern!{
+    // matches arrays of character literals
+    my_pattern_seq: Expr =
+        Array( Lit(_)*#foo )
+}
+```
+
+matches arrays that consist of any number of literal expressions. Because those
+expressions are named `foo`, the result struct contains a `foo` attribute which
+is a vector of expressions:
+
+```rust
+...
+if let Some(result) = my_pattern_seq(expr) {
+    result.foo        // type: Vec<&syntax::ast::Expr>
+}
+```
+
+Another result type occurs when a name is only defined in one branch of an
+alternation:
+
+```rust
+pattern!{
+    // matches if expression is a boolean or integer literal
+    my_pattern_alt: Expr =
+        Lit( Bool(_#bar) | Int(_) )
+}
+```
+
+In the pattern above, the `bar` name is only defined if the pattern matches a
+boolean literal. If it matches an integer literal, the name isn't set. To
+account for this, the result struct's `bar` attribute is an option type:
+
+```rust
+...
+if let Some(result) = my_pattern_alt(expr) {
+    result.bar        // type: Option<&bool>
+}
+```
+
+It's also possible to use a name in multiple alternation branches if they have
+compatible types:
+
+```rust
+pattern!{
+    // matches if expression is a boolean or integer literal
+    my_pattern_mult: Expr =
+        Lit(_#baz) | Array( Lit(_#baz) )
+}
+...
+if let Some(result) = my_pattern_mult(expr) {
+    result.baz        // type: &syntax::ast::Lit
+}
+```
+
+Named submatches are a **flat** namespace and this is intended. In the example
+above, two different sub-structures are assigned to a flat name. I expect that
+for most lints, a flat namespace is sufficient and easier to work with than a
+hierarchical one.
+
+#### Two stages
+
+Using named subpatterns, users can write lints in two stages. First, a coarse
+selection of possible matches is produced by the pattern syntax. In the second
+stage, the named subpattern references can be used to do additional tests like
+asserting that a node hasn't been created as part of a macro expansion.
+
+## Implementing clippy lints using patterns
+
+As a "real-world" example, I re-implemented the `collapsible_if` lint using
+patterns. The code can be found
+[here](https://github.com/fkohlgrueber/rust-clippy-pattern/blob/039b07ecccaf96d6aa7504f5126720d2c9cceddd/clippy_lints/src/collapsible_if.rs#L88-L163).
+The pattern-based version passes all test cases that were written for
+`collapsible_if`.
+
+
+# Reference-level explanation
+
+## Overview
+
+The following diagram shows the dependencies between the main parts of the
+proposed solution:
+
+```
+                          Pattern syntax
+                                |
+                                |  parsing / lowering
+                                v
+                           PatternTree
+                                ^
+                                |
+                                |
+                          IsMatch trait
+                                |
+                                |
+             +---------------+-----------+---------+
+             |               |           |         |
+             v               v           v         v
+        syntax::ast     rustc::hir      syn       ...
+```
+
+The pattern syntax described in the previous section is parsed / lowered into
+the so-called *PatternTree* data structure that represents a valid syntax tree
+pattern. Matching a *PatternTree* against an actual syntax tree (e.g. rust ast /
+hir or the syn ast, ...) is done using the *IsMatch* trait.
+
+The *PatternTree* and the *IsMatch* trait are introduced in more detail in the
+following sections.
+
+## PatternTree
+
+The core data structure of this RFC is the **PatternTree**.
+
+It's a data structure similar to rust's AST / HIR, but with the following
+differences:
+
+- The PatternTree doesn't contain parsing information like `Span`s
+- The PatternTree can represent alternatives, sequences and optionals
+
+The code below shows a simplified version of the current PatternTree:
+
+> Note: The current implementation can be found
+> [here](https://github.com/fkohlgrueber/pattern-matching/blob/dfb3bc9fbab69cec7c91e72564a63ebaa2ede638/pattern-match/src/pattern_tree.rs#L50-L96).
+
+
+```rust
+pub enum Expr {
+    Lit(Alt<Lit>),
+    Array(Seq<Expr>),
+    Block_(Alt<BlockType>),
+    If(Alt<Expr>, Alt<BlockType>, Opt<Expr>),
+    IfLet(
+        Alt<BlockType>,
+        Opt<Expr>,
+    ),
+}
+
+pub enum Lit {
+    Char(Alt<char>),
+    Bool(Alt<bool>),
+    Int(Alt<u128>),
+}
+
+pub enum Stmt {
+    Expr(Alt<Expr>),
+    Semi(Alt<Expr>),
+}
+
+pub enum BlockType {
+    Block(Seq<Stmt>),
+}
+```
+
+The `Alt`, `Seq` and `Opt` structs look like these:
+
+> Note: The current implementation can be found
+> [here](https://github.com/fkohlgrueber/pattern-matching/blob/dfb3bc9fbab69cec7c91e72564a63ebaa2ede638/pattern-match/src/matchers.rs#L35-L60).
+
+```rust
+pub enum Alt<T> {
+    Any,
+    Elmt(Box<T>),
+    Alt(Box<Self>, Box<Self>),
+    Named(Box<Self>, ...)
+}
+
+pub enum Opt<T> {
+    Any,  // anything, but not None
+    Elmt(Box<T>),
+    None,
+    Alt(Box<Self>, Box<Self>),
+    Named(Box<Self>, ...)
+}
+
+pub enum Seq<T> {
+    Any,
+    Empty,
+    Elmt(Box<T>),
+    Repeat(Box<Self>, RepeatRange),
+    Seq(Box<Self>, Box<Self>),
+    Alt(Box<Self>, Box<Self>),
+    Named(Box<Self>, ...)
+}
+
+pub struct RepeatRange {
+    pub start: usize,
+    pub end: Option<usize>  // exclusive
+}
+```
+
+## Parsing / Lowering
+
+The input of a `pattern!` macro call is parsed into a `ParseTree` first and then
+lowered to a `PatternTree`.
+
+Valid patterns depend on the *PatternTree* definitions. For example, the pattern
+`Lit(Bool(_)*)` isn't valid because the parameter type of the `Lit` variant of
+the `Expr` enum is `Any<Lit>` and therefore doesn't support repetition (`*`). As
+another example, `Array( Lit(_)* )` is a valid pattern because the parameter of
+`Array` is of type `Seq<Expr>` which allows sequences and repetitions.
+
+> Note: names in the pattern syntax correspond to *PatternTree* enum
+> **variants**. For example, the `Lit` in the pattern above refers to the `Lit`
+> variant of the `Expr` enum (`Expr::Lit`), not the `Lit` enum.
+
+## The IsMatch Trait
+
+The pattern syntax and the *PatternTree* are independant of specific syntax tree
+implementations (rust ast / hir, syn, ...). When looking at the different
+pattern examples in the previous sections, it can be seen that the patterns
+don't contain any information specific to a certain syntax tree implementation.
+In contrast, clippy lints currently match against ast / hir syntax tree nodes
+and therefore directly depend on their implementation.
+
+The connection between the *PatternTree* and specific syntax tree
+implementations is the `IsMatch` trait. It defines how to match *PatternTree*
+nodes against specific syntax tree nodes. A simplified implementation of the
+`IsMatch` trait is shown below:
+
+```rust
+pub trait IsMatch<O> {
+    fn is_match(&self, other: &'o O) -> bool;
+}
+```
+
+This trait needs to be implemented on each enum of the *PatternTree* (for the
+corresponding syntax tree types). For example, the `IsMatch` implementation for
+matching `ast::LitKind` against the *PatternTree's* `Lit` enum might look like
+this:
+
+```rust
+impl IsMatch<ast::LitKind> for Lit {
+    fn is_match(&self, other: &ast::LitKind) -> bool {
+        match (self, other) {
+            (Lit::Char(i), ast::LitKind::Char(j)) => i.is_match(j),
+            (Lit::Bool(i), ast::LitKind::Bool(j)) => i.is_match(j),
+            (Lit::Int(i), ast::LitKind::Int(j, _)) => i.is_match(j),
+            _ => false,
+        }
+    }
+}
+```
+
+All `IsMatch` implementations for matching the current *PatternTree* against
+`syntax::ast` can be found
+[here](https://github.com/fkohlgrueber/pattern-matching/blob/dfb3bc9fbab69cec7c91e72564a63ebaa2ede638/pattern-match/src/ast_match.rs).
+
+
+# Drawbacks
+
+#### Performance
+
+The pattern matching code is currently not optimized for performance, so it
+might be slower than hand-written matching code. Additionally, the two-stage
+approach (matching against the coarse pattern first and checking for additional
+properties later) might be slower than the current practice of checking for
+structure and additional properties in one pass. For example, the following lint
+
+```rust
+pattern!{
+    pat_if_without_else: Expr =
+        If(
+            _,
+            Block(
+                Expr( If(_, _, ())#inner )
+                | Semi( If(_, _, ())#inner )
+            )#then,
+            ()
+        )
+}
+...
+fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &ast::Expr) {
+    if let Some(result) = pat_if_without_else(expr) {
+        if !block_starts_with_comment(cx, result.then) {
+            ...
+        }
+}
+```
+
+first matches against the pattern and then checks that the `then` block doesn't
+start with a comment. Using clippy's current approach, it's possible to check
+for these conditions earlier:
+
+```rust
+fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &ast::Expr) {
+    if_chain! {
+        if let ast::ExprKind::If(ref check, ref then, None) = expr.node;
+        if !block_starts_with_comment(cx, then);
+        if let Some(inner) = expr_block(then);
+        if let ast::ExprKind::If(ref check_inner, ref content, None) = inner.node;
+        then {
+            ...
+        }
+    }
+}
+```
+
+Whether or not this causes performance regressions depends on actual patterns.
+If it turns out to be a problem, the pattern matching algorithms could be
+extended to allow "early filtering" (see the [Early Filtering](#early-filtering)
+section in Future Possibilities).
+
+That being said, I don't see any conceptual limitations regarding pattern
+matching performance.
+
+#### Applicability
+
+Even though I'd expect that a lot of lints can be written using the proposed
+pattern syntax, it's unlikely that all lints can be expressed using patterns. I
+suspect that there will still be lints that need to be implemented by writing
+custom pattern matching code. This would lead to mix within clippy's codebase
+where some lints are implemented using patterns and others aren't. This
+inconsistency might be considered a drawback.
+
+
+# Rationale and alternatives
+
+Specifying lints using syntax tree patterns has a couple of advantages compared
+to the current approach of manually writing matching code. First, syntax tree
+patterns allow users to describe patterns in a simple and expressive way. This
+makes it easier to write new lints for both novices and experts and also makes
+reading / modifying existing lints simpler.
+
+Another advantage is that lints are independent of specific syntax tree
+implementations (e.g. AST / HIR, ...). When these syntax tree implementations
+change, only the `IsMatch` trait implementations need to be adapted and existing
+lints can remain unchanged. This also means that if the `IsMatch` trait
+implementations were integrated into the compiler, updating the `IsMatch`
+implementations would be required for the compiler to compile successfully. This
+could reduce the number of times clippy breaks because of changes in the
+compiler. Another advantage of the pattern's independence is that converting an
+`EarlyLintPass` lint into a `LatePassLint` wouldn't require rewriting the whole
+pattern matching code. In fact, the pattern might work just fine without any
+adaptions.
+
+
+## Alternatives
+
+### Rust-like pattern syntax
+
+The proposed pattern syntax requires users to know the structure of the
+`PatternTree` (which is very similar to the AST's / HIR's structure) and also
+the pattern syntax. An alternative would be to introduce a pattern syntax that
+is similar to actual Rust syntax (probably like the `quote!` macro). For
+example, a pattern that matches `if` expressions that have `false` in their
+condition could look like this:
+
+```rust
+if false {
+    #[*]
+}
+```
+
+#### Problems
+
+Extending Rust syntax (which is quite complex by itself) with additional syntax
+needed for specifying patterns (alternations, sequences, repetisions, named
+submatches, ...) might become difficult to read and really hard to parse
+properly.
+
+For example, a pattern that matches a binary operation that has `0` on both
+sides might look like this:
+
+```
+0 #[*:BinOpKind] 0
+```
+
+Now consider this slightly more complex example:
+
+```
+1 + 0 #[*:BinOpKind] 0
+```
+
+The parser would need to know the precedence of `#[*:BinOpKind]` because it
+affects the structure of the resulting AST. `1 + 0 + 0` is parsed as `(1 + 0) +
+0` while `1 + 0 * 0` is parsed as `1 + (0 * 0)`. Since the pattern could be any
+`BinOpKind`, the precedence cannot be known in advance.
+
+Another example of a problem would be named submatches. Take a look at this
+pattern:
+
+```rust
+fn test() {
+    1 #foo
+}
+```
+
+Which node is `#foo` referring to? `int`, `ast::Lit`, `ast::Expr`, `ast::Stmt`?
+Naming subpatterns in a rust-like syntax is difficult because a lot of AST nodes
+don't have a syntactic element that can be used to put the name tag on. In these
+situations, the only sensible option would be to assign the name tag to the
+outermost node (`ast::Stmt` in the example above), because the information of
+all child nodes can be retrieved through the outermost node. The problem with
+this then would be that accessing inner nodes (like `ast::Lit`) would again
+require manual pattern matching.
+
+In general, Rust syntax contains a lot of code structure implicitly. This
+structure is reconstructed during parsing (e.g. binary operations are
+reconstructed using operator precedence and left-to-right) and is one of the
+reasons why parsing is a complex task. The advantage of this approach is that
+writing code is simpler for users.
+
+When writing *syntax tree patterns*, each element of the hierarchy might have
+alternatives, repetitions, etc.. Respecting that while still allowing
+human-friendly syntax that contains structure implicitly seems to be really
+complex, if not impossible.
+
+Developing such a syntax would also require to maintain a custom parser that is
+at least as complex as the Rust parser itself. Additionally, future changes in
+the Rust syntax might be incompatible with such a syntax.
+
+In summary, I think that developing such a syntax would introduce a lot of
+complexity to solve a relatively minor problem.
+
+The issue of users not knowing about the *PatternTree* structure could be solved
+by a tool that, given a rust program, generates a pattern that matches only this
+program (similar to the clippy author lint).
+
+For some simple cases (like the first example above), it might be possible to
+successfully mix Rust and pattern syntax. This space could be further explored
+in a future extension.
+
+# Prior art
+
+The pattern syntax is heavily inspired by regular expressions (repetitions,
+alternatives, sequences, ...).
+
+From what I've seen until now, other linters also implement lints that directly
+work on syntax tree data structures, just like clippy does currently. I would
+therefore consider the pattern syntax to be *new*, but please correct me if I'm
+wrong.
+
+# Unresolved questions
+
+#### How to handle multiple matches?
+
+When matching a syntax tree node against a pattern, there are possibly multiple
+ways in which the pattern can be matched. A simple example of this would be the
+following pattern:
+
+```rust
+pattern!{
+    my_pattern: Expr =
+        Array( _* Lit(_)+#literals)
+}
+```
+
+This pattern matches arrays that end with at least one literal. Now given the
+array `[x, 1, 2]`, should `1` be matched as part of the `_*` or the `Lit(_)+`
+part of the pattern? The difference is important because the named submatch
+`#literals` would contain 1 or 2 elements depending how the pattern is matched.
+In regular expressions, this problem is solved by matching "greedy" by default
+and "non-greedy" optionally.
+
+I haven't looked much into this yet because I don't know how relevant it is for
+most lints. The current implementation simply returns the first match it finds.
+
+# Future possibilities
+
+#### Implement rest of Rust Syntax
+
+The current project only implements a small part of the Rust syntax. In the
+future, this should incrementally be extended to more syntax to allow
+implementing more lints. Implementing more of the Rust syntax requires extending
+the `PatternTree` and `IsMatch` implementations, but should be relatively
+straight-forward.
+
+#### Early filtering
+
+As described in the *Drawbacks/Performance* section, allowing additional checks
+during the pattern matching might be beneficial.
+
+The pattern below shows how this could look like:
+
+```rust
+pattern!{
+    pat_if_without_else: Expr =
+        If(
+            _,
+            Block(
+                Expr( If(_, _, ())#inner )
+                | Semi( If(_, _, ())#inner )
+            )#then,
+            ()
+        )
+    where
+        !in_macro(#then.span);
+}
+```
+
+The difference compared to the currently proposed two-stage filtering is that
+using early filtering, the condition (`!in_macro(#then.span)` in this case)
+would be evaluated as soon as the `Block(_)#then` was matched.
+
+Another idea in this area would be to introduce a syntax for backreferences.
+They could be used to require that multiple parts of a pattern should match the
+same value. For example, the `assign_op_pattern` lint that searches for `a = a
+op b` and recommends changing it to `a op= b` requires that both occurrances of
+`a` are the same. Using `=#...` as syntax for backreferences, the lint could be
+implemented like this:
+
+```rust
+pattern!{
+    assign_op_pattern: Expr =
+        Assign(_#target, Binary(_, =#target, _)
+}
+```
+
+#### Match descendant
+
+A lot of lints currently implement custom visitors that check whether any
+subtree (which might not be a direct descendant) of the current node matches
+some properties. This cannot be expressed with the proposed pattern syntax.
+Extending the pattern syntax to allow patterns like "a function that contains at
+least two return statements" could be a practical addition.
+
+#### Negation operator for alternatives
+
+For patterns like "a literal that is not a boolean literal" one currently needs
+to list all alternatives except the boolean case. Introducing a negation
+operator that allows to write `Lit(!Bool(_))` might be a good idea. This pattern
+would be eqivalent to `Lit( Char(_) | Int(_) )` (given that currently only three
+literal types are implemented).
+
+#### Functional composition
+
+Patterns currently don't have any concept of composition. This leads to
+repetitions within patterns. For example, one of the collapsible-if patterns
+currently has to be written like this:
+
+```rust
+pattern!{
+    pat_if_else: Expr =
+        If(
+            _,
+            _,
+            Block_(
+                Block(
+                    Expr((If(_, _, _?) | IfLet(_, _?))#else_) |
+                    Semi((If(_, _, _?) | IfLet(_, _?))#else_)
+                )#block_inner
+            )#block
+        ) |
+        IfLet(
+            _,
+            Block_(
+                Block(
+                    Expr((If(_, _, _?) | IfLet(_, _?))#else_) |
+                    Semi((If(_, _, _?) | IfLet(_, _?))#else_)
+                )#block_inner
+            )#block
+        )
+}
+```
+
+If patterns supported defining functions of subpatterns, the code could be
+simplified as follows:
+
+```rust
+pattern!{
+    fn expr_or_semi(expr: Expr) -> Stmt {
+        Expr(expr) | Semi(expr)
+    }
+    fn if_or_if_let(then: Block, else: Opt<Expr>) -> Expr {
+        If(_, then, else) | IfLet(then, else)
+    }
+    pat_if_else: Expr =
+        if_or_if_let(
+            _,
+            Block_(
+                Block(
+                    expr_or_semi( if_or_if_let(_, _?)#else_ )
+                )#block_inner
+            )#block
+        )
+}
+```
+
+Additionally, common patterns like `expr_or_semi` could be shared between
+different lints.
+
+#### Clippy Pattern Author
+
+Another improvement could be to create a tool that, given some valid Rust
+syntax, generates a pattern that matches this syntax exactly. This would make
+starting to write a pattern easier. A user could take a look at the patterns
+generated for a couple of Rust code examples and use that information to write a
+pattern that matches all of them.
+
+This is similar to clippy's author lint.
+
+#### Supporting other syntaxes
+
+Most of the proposed system is language-agnostic. For example, the pattern
+syntax could also be used to describe patterns for other programming languages.
+
+In order to support other languages' syntaxes, one would need to implement
+another `PatternTree` that sufficiently describes the languages' AST and
+implement `IsMatch` for this `PatternTree` and the languages' AST.
+
+One aspect of this is that it would even be possible to write lints that work on
+the pattern syntax itself. For example, when writing the following pattern
+
+
+```rust
+pattern!{
+    my_pattern: Expr =
+        Array( Lit(Bool(false)) Lit(Bool(false)) )
+}
+```
+
+a lint that works on the pattern syntax's AST could suggest using this pattern
+instead:
+
+```rust
+pattern!{
+    my_pattern: Expr =
+        Array( Lit(Bool(false)){2} )
+}
+```
+
+In the future, clippy could use this system to also provide lints for custom
+syntaxes like those found in macros.
index 9e15f1504fa91f6e6f2c883380f52d5355862c7a..ec7f1dd0d846cbe8a0f87ad50c43e733ebfec59a 100644 (file)
@@ -120,7 +120,7 @@ fn add_lint(lint: &LintData<'_>, enable_msrv: bool) -> io::Result<()> {
 
     let new_lint = if enable_msrv {
         format!(
-            "store.register_{lint_pass}_pass(move |{ctor_arg}| Box::new({module_name}::{camel_name}::new(msrv)));\n    ",
+            "store.register_{lint_pass}_pass(move |{ctor_arg}| Box::new({module_name}::{camel_name}::new(msrv())));\n    ",
             lint_pass = lint.pass,
             ctor_arg = if lint.pass == "late" { "_" } else { "" },
             module_name = lint.name,
@@ -238,10 +238,9 @@ fn get_lint_file_contents(lint: &LintData<'_>, enable_msrv: bool) -> String {
     result.push_str(&if enable_msrv {
         formatdoc!(
             r#"
-            use clippy_utils::msrvs;
+            use clippy_utils::msrvs::{{self, Msrv}};
             {pass_import}
             use rustc_lint::{{{context_import}, {pass_type}, LintContext}};
-            use rustc_semver::RustcVersion;
             use rustc_session::{{declare_tool_lint, impl_lint_pass}};
 
         "#
@@ -263,12 +262,12 @@ fn get_lint_file_contents(lint: &LintData<'_>, enable_msrv: bool) -> String {
         formatdoc!(
             r#"
             pub struct {name_camel} {{
-                msrv: Option<RustcVersion>,
+                msrv: Msrv,
             }}
 
             impl {name_camel} {{
                 #[must_use]
-                pub fn new(msrv: Option<RustcVersion>) -> Self {{
+                pub fn new(msrv: Msrv) -> Self {{
                     Self {{ msrv }}
                 }}
             }}
@@ -357,15 +356,14 @@ fn create_lint_for_ty(lint: &LintData<'_>, enable_msrv: bool, ty: &str) -> io::R
         let _ = writedoc!(
             lint_file_contents,
             r#"
-                use clippy_utils::{{meets_msrv, msrvs}};
+                use clippy_utils::msrvs::{{self, Msrv}};
                 use rustc_lint::{{{context_import}, LintContext}};
-                use rustc_semver::RustcVersion;
 
                 use super::{name_upper};
 
                 // TODO: Adjust the parameters as necessary
-                pub(super) fn check(cx: &{context_import}, msrv: Option<RustcVersion>) {{
-                    if !meets_msrv(msrv, todo!("Add a new entry in `clippy_utils/src/msrvs`")) {{
+                pub(super) fn check(cx: &{context_import}, msrv: &Msrv) {{
+                    if !msrv.meets(todo!("Add a new entry in `clippy_utils/src/msrvs`")) {{
                         return;
                     }}
                     todo!();
index df92579a85df280a7846addaad0aa94045ed4fc1..52beaf504a4e0deb6ff0f17e5bf387d463e05d9f 100644 (file)
@@ -1,11 +1,10 @@
 use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::msrvs::{self, Msrv};
 use clippy_utils::source::{trim_span, walk_span_to_context};
-use clippy_utils::{meets_msrv, msrvs};
 use rustc_ast::ast::{Expr, ExprKind, LitKind, Pat, PatKind, RangeEnd, RangeLimits};
 use rustc_errors::Applicability;
 use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
 use rustc_middle::lint::in_external_macro;
-use rustc_semver::RustcVersion;
 use rustc_session::{declare_tool_lint, impl_lint_pass};
 use rustc_span::Span;
 
 impl_lint_pass!(AlmostCompleteLetterRange => [ALMOST_COMPLETE_LETTER_RANGE]);
 
 pub struct AlmostCompleteLetterRange {
-    msrv: Option<RustcVersion>,
+    msrv: Msrv,
 }
 impl AlmostCompleteLetterRange {
-    pub fn new(msrv: Option<RustcVersion>) -> Self {
+    pub fn new(msrv: Msrv) -> Self {
         Self { msrv }
     }
 }
@@ -46,7 +45,7 @@ fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &Expr) {
             let ctxt = e.span.ctxt();
             let sugg = if let Some(start) = walk_span_to_context(start.span, ctxt)
                 && let Some(end) = walk_span_to_context(end.span, ctxt)
-                && meets_msrv(self.msrv, msrvs::RANGE_INCLUSIVE)
+                && self.msrv.meets(msrvs::RANGE_INCLUSIVE)
             {
                 Some((trim_span(cx.sess().source_map(), start.between(end)), "..="))
             } else {
@@ -60,7 +59,7 @@ fn check_pat(&mut self, cx: &EarlyContext<'_>, p: &Pat) {
         if let PatKind::Range(Some(start), Some(end), kind) = &p.kind
             && matches!(kind.node, RangeEnd::Excluded)
         {
-            let sugg = if meets_msrv(self.msrv, msrvs::RANGE_INCLUSIVE) {
+            let sugg = if self.msrv.meets(msrvs::RANGE_INCLUSIVE) {
                 "..="
             } else {
                 "..."
index 724490fb49592f64c5b770de45124e741dcb08c0..ccf82f132f4e42dd1af0b6a533c678dd757e2337 100644 (file)
@@ -1,5 +1,5 @@
 use clippy_utils::diagnostics::span_lint_and_help;
-use clippy_utils::{meets_msrv, msrvs};
+use clippy_utils::msrvs::{self, Msrv};
 use rustc_ast::ast::{FloatTy, LitFloatType, LitKind};
 use rustc_hir::{Expr, ExprKind};
 use rustc_lint::{LateContext, LateLintPass};
 ];
 
 pub struct ApproxConstant {
-    msrv: Option<RustcVersion>,
+    msrv: Msrv,
 }
 
 impl ApproxConstant {
     #[must_use]
-    pub fn new(msrv: Option<RustcVersion>) -> Self {
+    pub fn new(msrv: Msrv) -> Self {
         Self { msrv }
     }
 
@@ -87,7 +87,7 @@ fn check_known_consts(&self, cx: &LateContext<'_>, e: &Expr<'_>, s: symbol::Symb
         let s = s.as_str();
         if s.parse::<f64>().is_ok() {
             for &(constant, name, min_digits, msrv) in &KNOWN_CONSTS {
-                if is_approx_const(constant, s, min_digits) && msrv.map_or(true, |msrv| meets_msrv(self.msrv, msrv)) {
+                if is_approx_const(constant, s, min_digits) && msrv.map_or(true, |msrv| self.msrv.meets(msrv)) {
                     span_lint_and_help(
                         cx,
                         APPROX_CONSTANT,
index 018f10f258867872816e22b5f9604ee0cbc57a0f..0710ac0bb0a72468bb8144351560972dcf53a55a 100644 (file)
@@ -2,9 +2,8 @@
 
 use clippy_utils::diagnostics::{span_lint, span_lint_and_help, span_lint_and_sugg, span_lint_and_then};
 use clippy_utils::macros::{is_panic, macro_backtrace};
-use clippy_utils::msrvs;
+use clippy_utils::msrvs::{self, Msrv};
 use clippy_utils::source::{first_line_of_span, is_present_in_source, snippet_opt, without_block_comments};
-use clippy_utils::{extract_msrv_attr, meets_msrv};
 use if_chain::if_chain;
 use rustc_ast::{AttrKind, AttrStyle, Attribute, LitKind, MetaItemKind, MetaItemLit, NestedMetaItem};
 use rustc_errors::Applicability;
@@ -14,7 +13,6 @@
 use rustc_lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, Level, LintContext};
 use rustc_middle::lint::in_external_macro;
 use rustc_middle::ty;
-use rustc_semver::RustcVersion;
 use rustc_session::{declare_lint_pass, declare_tool_lint, impl_lint_pass};
 use rustc_span::source_map::Span;
 use rustc_span::symbol::Symbol;
@@ -599,7 +597,7 @@ fn is_word(nmi: &NestedMetaItem, expected: Symbol) -> bool {
 }
 
 pub struct EarlyAttributes {
-    pub msrv: Option<RustcVersion>,
+    pub msrv: Msrv,
 }
 
 impl_lint_pass!(EarlyAttributes => [
@@ -614,7 +612,7 @@ fn check_item(&mut self, cx: &EarlyContext<'_>, item: &rustc_ast::Item) {
     }
 
     fn check_attribute(&mut self, cx: &EarlyContext<'_>, attr: &Attribute) {
-        check_deprecated_cfg_attr(cx, attr, self.msrv);
+        check_deprecated_cfg_attr(cx, attr, &self.msrv);
         check_mismatched_target_os(cx, attr);
     }
 
@@ -654,9 +652,9 @@ fn check_empty_line_after_outer_attr(cx: &EarlyContext<'_>, item: &rustc_ast::It
     }
 }
 
-fn check_deprecated_cfg_attr(cx: &EarlyContext<'_>, attr: &Attribute, msrv: Option<RustcVersion>) {
+fn check_deprecated_cfg_attr(cx: &EarlyContext<'_>, attr: &Attribute, msrv: &Msrv) {
     if_chain! {
-        if meets_msrv(msrv, msrvs::TOOL_ATTRIBUTES);
+        if msrv.meets(msrvs::TOOL_ATTRIBUTES);
         // check cfg_attr
         if attr.has_name(sym::cfg_attr);
         if let Some(items) = attr.meta_item_list();
index 3f1edabe6c5040621bb2903b0df2e2ea07843270..442262983337686fab42a2e0482d41cba26cdf8f 100644 (file)
@@ -1,11 +1,10 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::msrvs::{self, Msrv};
 use clippy_utils::sugg::Sugg;
-use clippy_utils::{meets_msrv, msrvs};
 use rustc_errors::Applicability;
 use rustc_hir::{Expr, ExprKind};
 use rustc_lint::LateContext;
 use rustc_middle::ty::{self, Ty};
-use rustc_semver::RustcVersion;
 
 use super::CAST_ABS_TO_UNSIGNED;
 
@@ -15,9 +14,9 @@ pub(super) fn check(
     cast_expr: &Expr<'_>,
     cast_from: Ty<'_>,
     cast_to: Ty<'_>,
-    msrv: Option<RustcVersion>,
+    msrv: &Msrv,
 ) {
-    if meets_msrv(msrv, msrvs::UNSIGNED_ABS)
+    if msrv.meets(msrvs::UNSIGNED_ABS)
         && let ty::Int(from) = cast_from.kind()
         && let ty::Uint(to) = cast_to.kind()
         && let ExprKind::MethodCall(method_path, receiver, ..) = cast_expr.kind
index 13c403234dad5e8b44a41dfe87b99a5f24d25b4b..cf07e050ccce99e6966ae2d9b2ec55a32df8067e 100644 (file)
@@ -1,12 +1,12 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::in_constant;
+use clippy_utils::msrvs::{self, Msrv};
 use clippy_utils::source::snippet_opt;
 use clippy_utils::ty::is_isize_or_usize;
-use clippy_utils::{in_constant, meets_msrv, msrvs};
 use rustc_errors::Applicability;
 use rustc_hir::{Expr, ExprKind};
 use rustc_lint::LateContext;
 use rustc_middle::ty::{self, FloatTy, Ty};
-use rustc_semver::RustcVersion;
 
 use super::{utils, CAST_LOSSLESS};
 
@@ -16,7 +16,7 @@ pub(super) fn check(
     cast_op: &Expr<'_>,
     cast_from: Ty<'_>,
     cast_to: Ty<'_>,
-    msrv: Option<RustcVersion>,
+    msrv: &Msrv,
 ) {
     if !should_lint(cx, expr, cast_from, cast_to, msrv) {
         return;
@@ -57,13 +57,7 @@ pub(super) fn check(
     );
 }
 
-fn should_lint(
-    cx: &LateContext<'_>,
-    expr: &Expr<'_>,
-    cast_from: Ty<'_>,
-    cast_to: Ty<'_>,
-    msrv: Option<RustcVersion>,
-) -> bool {
+fn should_lint(cx: &LateContext<'_>, expr: &Expr<'_>, cast_from: Ty<'_>, cast_to: Ty<'_>, msrv: &Msrv) -> bool {
     // Do not suggest using From in consts/statics until it is valid to do so (see #2267).
     if in_constant(cx, expr.hir_id) {
         return false;
@@ -89,7 +83,7 @@ fn should_lint(
             };
             !is_isize_or_usize(cast_from) && from_nbits < to_nbits
         },
-        (false, true) if matches!(cast_from.kind(), ty::Bool) && meets_msrv(msrv, msrvs::FROM_BOOL) => true,
+        (false, true) if matches!(cast_from.kind(), ty::Bool) && msrv.meets(msrvs::FROM_BOOL) => true,
         (_, _) => {
             matches!(cast_from.kind(), ty::Float(FloatTy::F32)) && matches!(cast_to.kind(), ty::Float(FloatTy::F64))
         },
index adbcfd3189b76d0fad22532f0e767fe7e63a7932..a6376484914ba11dad3b13e0ef9fe649a9f8493c 100644 (file)
@@ -118,12 +118,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>,
             };
             let to_nbits = utils::int_ty_to_nbits(cast_to, cx.tcx);
 
-            let cast_from_ptr_size = def.repr().int.map_or(true, |ty| {
-                matches!(
-                    ty,
-                    IntegerType::Pointer(_),
-                )
-            });
+            let cast_from_ptr_size = def.repr().int.map_or(true, |ty| matches!(ty, IntegerType::Pointer(_),));
             let suffix = match (cast_from_ptr_size, is_isize_or_usize(cast_to)) {
                 (false, false) if from_nbits > to_nbits => "",
                 (true, false) if from_nbits > to_nbits => "",
index d31d10d22b92b8997a77631d71d86ddc21dcdd38..e862f13e69fc7059011014ad82f3310e8666ea73 100644 (file)
@@ -1,16 +1,16 @@
-use clippy_utils::{diagnostics::span_lint_and_then, meets_msrv, msrvs, source};
+use clippy_utils::msrvs::{self, Msrv};
+use clippy_utils::{diagnostics::span_lint_and_then, source};
 use if_chain::if_chain;
 use rustc_ast::Mutability;
 use rustc_hir::{Expr, ExprKind, Node};
 use rustc_lint::LateContext;
 use rustc_middle::ty::{self, layout::LayoutOf, Ty, TypeAndMut};
-use rustc_semver::RustcVersion;
 
 use super::CAST_SLICE_DIFFERENT_SIZES;
 
-pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>, msrv: Option<RustcVersion>) {
+pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>, msrv: &Msrv) {
     // suggestion is invalid if `ptr::slice_from_raw_parts` does not exist
-    if !meets_msrv(msrv, msrvs::PTR_SLICE_RAW_PARTS) {
+    if !msrv.meets(msrvs::PTR_SLICE_RAW_PARTS) {
         return;
     }
 
index 284ef165998a7f46cbfaa7b9060cb81dc42fe9a7..627b795d6edd8f5ea04603bfead49042878ff7c5 100644 (file)
@@ -1,12 +1,12 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::msrvs::{self, Msrv};
 use clippy_utils::source::snippet_with_applicability;
-use clippy_utils::{match_def_path, meets_msrv, msrvs, paths};
+use clippy_utils::{match_def_path, 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;
 
@@ -25,15 +25,9 @@ fn raw_parts_kind(cx: &LateContext<'_>, did: DefId) -> Option<RawPartsKind> {
     }
 }
 
-pub(super) fn check(
-    cx: &LateContext<'_>,
-    expr: &Expr<'_>,
-    cast_expr: &Expr<'_>,
-    cast_to: Ty<'_>,
-    msrv: Option<RustcVersion>,
-) {
+pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>, cast_to: Ty<'_>, msrv: &Msrv) {
     if_chain! {
-        if meets_msrv(msrv, msrvs::PTR_SLICE_RAW_PARTS);
+        if msrv.meets(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;
index 7148b5e6ebf45e09c2da8693aaf6184410ec6bbc..c6d505c4a181fc2e3b52c2be3b1d713f7123eec2 100644 (file)
 mod unnecessary_cast;
 mod utils;
 
-use clippy_utils::{is_hir_ty_cfg_dependant, meets_msrv, msrvs};
+use clippy_utils::is_hir_ty_cfg_dependant;
+use clippy_utils::msrvs::{self, Msrv};
 use rustc_hir::{Expr, ExprKind};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
 use rustc_middle::lint::in_external_macro;
-use rustc_semver::RustcVersion;
 use rustc_session::{declare_tool_lint, impl_lint_pass};
 
 declare_clippy_lint! {
 }
 
 pub struct Casts {
-    msrv: Option<RustcVersion>,
+    msrv: Msrv,
 }
 
 impl Casts {
     #[must_use]
-    pub fn new(msrv: Option<RustcVersion>) -> Self {
+    pub fn new(msrv: Msrv) -> Self {
         Self { msrv }
     }
 }
@@ -686,7 +686,7 @@ pub fn new(msrv: Option<RustcVersion>) -> Self {
 impl<'tcx> LateLintPass<'tcx> for Casts {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
         if !in_external_macro(cx.sess(), expr.span) {
-            ptr_as_ptr::check(cx, expr, self.msrv);
+            ptr_as_ptr::check(cx, expr, &self.msrv);
         }
 
         if expr.span.from_expansion() {
@@ -705,7 +705,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);
+            cast_slice_from_raw_parts::check(cx, expr, cast_expr, cast_to, &self.msrv);
             as_ptr_cast_mut::check(cx, expr, cast_expr, cast_to);
             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);
@@ -717,16 +717,16 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
                     cast_possible_wrap::check(cx, expr, cast_from, cast_to);
                     cast_precision_loss::check(cx, expr, cast_from, cast_to);
                     cast_sign_loss::check(cx, expr, cast_expr, cast_from, cast_to);
-                    cast_abs_to_unsigned::check(cx, expr, cast_expr, cast_from, cast_to, self.msrv);
+                    cast_abs_to_unsigned::check(cx, expr, cast_expr, cast_from, cast_to, &self.msrv);
                     cast_nan_to_int::check(cx, expr, cast_expr, cast_from, cast_to);
                 }
-                cast_lossless::check(cx, expr, cast_expr, cast_from, cast_to, self.msrv);
+                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) {
+            if self.msrv.meets(msrvs::BORROW_AS_PTR) {
                 borrow_as_ptr::check(cx, expr, cast_expr, cast_to_hir);
             }
         }
@@ -734,8 +734,8 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
         cast_ref_to_mut::check(cx, expr);
         cast_ptr_alignment::check(cx, expr);
         char_lit_as_u8::check(cx, expr);
-        ptr_as_ptr::check(cx, expr, self.msrv);
-        cast_slice_different_sizes::check(cx, expr, self.msrv);
+        ptr_as_ptr::check(cx, expr, &self.msrv);
+        cast_slice_different_sizes::check(cx, expr, &self.msrv);
     }
 
     extract_msrv_attr!(LateContext);
index b9509ca656f7a170117e115cf0a6cd47023eee80..15ffb00da88bacd80d7bb5016cde42db203ba221 100644 (file)
@@ -1,19 +1,18 @@
 use std::borrow::Cow;
 
 use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::msrvs::{self, Msrv};
 use clippy_utils::sugg::Sugg;
-use clippy_utils::{meets_msrv, msrvs};
 use if_chain::if_chain;
 use rustc_errors::Applicability;
 use rustc_hir::{Expr, ExprKind, Mutability, TyKind};
 use rustc_lint::LateContext;
 use rustc_middle::ty::{self, TypeAndMut};
-use rustc_semver::RustcVersion;
 
 use super::PTR_AS_PTR;
 
-pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, msrv: Option<RustcVersion>) {
-    if !meets_msrv(msrv, msrvs::POINTER_CAST) {
+pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, msrv: &Msrv) {
+    if !msrv.meets(msrvs::POINTER_CAST) {
         return;
     }
 
index c8596987e4d719b158aa879d7f1bc2bf452d4c16..7e23318076cf2e8b9aa6ec5247b39d2268c3ca38 100644 (file)
@@ -1,7 +1,7 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::get_parent_expr;
 use clippy_utils::numeric_literal::NumericLiteral;
 use clippy_utils::source::snippet_opt;
+use clippy_utils::{get_parent_expr, path_to_local};
 use if_chain::if_chain;
 use rustc_ast::{LitFloatType, LitIntType, LitKind};
 use rustc_errors::Applicability;
@@ -75,13 +75,26 @@ pub(super) fn check<'tcx>(
     }
 
     if cast_from.kind() == cast_to.kind() && !in_external_macro(cx.sess(), expr.span) {
+        if let Some(id) = path_to_local(cast_expr)
+            && let Some(span) = cx.tcx.hir().opt_span(id)
+            && span.ctxt() != cast_expr.span.ctxt()
+        {
+            // Binding context is different than the identifiers context.
+            // Weird macro wizardry could be involved here.
+            return false;
+        }
+
         span_lint_and_sugg(
             cx,
             UNNECESSARY_CAST,
             expr.span,
             &format!("casting to the same type is unnecessary (`{cast_from}` -> `{cast_to}`)"),
             "try",
-            cast_str,
+            if get_parent_expr(cx, expr).map_or(false, |e| matches!(e.kind, ExprKind::AddrOf(..))) {
+                format!("{{ {cast_str} }}")
+            } else {
+                cast_str
+            },
             Applicability::MachineApplicable,
         );
         return true;
index 78e9921f036f3369bd3f5768bb96227c01430fcd..9102a89e37726ab035c349a6768c25bddd0cb796 100644 (file)
@@ -1,14 +1,14 @@
 //! lint on manually implemented checked conversions that could be transformed into `try_from`
 
 use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::msrvs::{self, Msrv};
 use clippy_utils::source::snippet_with_applicability;
-use clippy_utils::{in_constant, is_integer_literal, meets_msrv, msrvs, SpanlessEq};
+use clippy_utils::{in_constant, is_integer_literal, SpanlessEq};
 use if_chain::if_chain;
 use rustc_errors::Applicability;
 use rustc_hir::{BinOp, BinOpKind, Expr, ExprKind, QPath, TyKind};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
 use rustc_middle::lint::in_external_macro;
-use rustc_semver::RustcVersion;
 use rustc_session::{declare_tool_lint, impl_lint_pass};
 
 declare_clippy_lint! {
 }
 
 pub struct CheckedConversions {
-    msrv: Option<RustcVersion>,
+    msrv: Msrv,
 }
 
 impl CheckedConversions {
     #[must_use]
-    pub fn new(msrv: Option<RustcVersion>) -> Self {
+    pub fn new(msrv: Msrv) -> Self {
         Self { msrv }
     }
 }
@@ -51,7 +51,7 @@ pub fn new(msrv: Option<RustcVersion>) -> Self {
 
 impl<'tcx> LateLintPass<'tcx> for CheckedConversions {
     fn check_expr(&mut self, cx: &LateContext<'_>, item: &Expr<'_>) {
-        if !meets_msrv(self.msrv, msrvs::TRY_FROM) {
+        if !self.msrv.meets(msrvs::TRY_FROM) {
             return;
         }
 
index 90430b71a0ef99638596bfa9ea7ac840fe035867..b38e09dc09f46e5d2053f8080b3e87e2f17844e4 100644 (file)
@@ -160,11 +160,13 @@ fn check_collapsible_no_if_let(cx: &EarlyContext<'_>, expr: &ast::Expr, check: &
         if let ast::ExprKind::If(ref check_inner, ref content, None) = inner.kind;
         // Prevent triggering on `if c { if let a = b { .. } }`.
         if !matches!(check_inner.kind, ast::ExprKind::Let(..));
-        if expr.span.ctxt() == inner.span.ctxt();
+        let ctxt = expr.span.ctxt();
+        if inner.span.ctxt() == ctxt;
         then {
             span_lint_and_then(cx, COLLAPSIBLE_IF, expr.span, "this `if` statement can be collapsed", |diag| {
-                let lhs = Sugg::ast(cx, check, "..");
-                let rhs = Sugg::ast(cx, check_inner, "..");
+                let mut app = Applicability::MachineApplicable;
+                let lhs = Sugg::ast(cx, check, "..", ctxt, &mut app);
+                let rhs = Sugg::ast(cx, check_inner, "..", ctxt, &mut app);
                 diag.span_suggestion(
                     expr.span,
                     "collapse nested if block",
@@ -173,7 +175,7 @@ fn check_collapsible_no_if_let(cx: &EarlyContext<'_>, expr: &ast::Expr, check: &
                         lhs.and(&rhs),
                         snippet_block(cx, content.span, "..", Some(expr.span)),
                     ),
-                    Applicability::MachineApplicable, // snippet
+                    app, // snippet
                 );
             });
         }
index 0d3fc43a6443b69f23e38a42eb3569411aad39b1..e4d76f07d6b482b13fa7d5fbaf9cb8b6ce9923fd 100644 (file)
     crate::from_raw_with_void_ptr::FROM_RAW_WITH_VOID_PTR_INFO,
     crate::from_str_radix_10::FROM_STR_RADIX_10_INFO,
     crate::functions::DOUBLE_MUST_USE_INFO,
+    crate::functions::MISNAMED_GETTERS_INFO,
     crate::functions::MUST_USE_CANDIDATE_INFO,
     crate::functions::MUST_USE_UNIT_INFO,
     crate::functions::NOT_UNSAFE_PTR_ARG_DEREF_INFO,
     crate::types::TYPE_COMPLEXITY_INFO,
     crate::types::VEC_BOX_INFO,
     crate::undocumented_unsafe_blocks::UNDOCUMENTED_UNSAFE_BLOCKS_INFO,
+    crate::undocumented_unsafe_blocks::UNNECESSARY_SAFETY_COMMENT_INFO,
     crate::unicode::INVISIBLE_CHARACTERS_INFO,
     crate::unicode::NON_ASCII_LITERAL_INFO,
     crate::unicode::UNICODE_NOT_NFC_INFO,
index 47ea98956be24cc98b6c5e41d59a6b6a4badc646..38329659e02b76108ed46d071dd49f38c2a04650 100644 (file)
@@ -1,12 +1,13 @@
 use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_hir_and_then};
 use clippy_utils::mir::{enclosing_mir, expr_local, local_assignments, used_exactly_once, PossibleBorrowerMap};
+use clippy_utils::msrvs::{self, Msrv};
 use clippy_utils::source::{snippet_with_applicability, snippet_with_context};
 use clippy_utils::sugg::has_enclosing_paren;
 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,
+    fn_def_id, get_parent_expr, get_parent_expr_for_hir, is_lint_allowed, path_to_local, walk_to_expr_usage,
 };
+
 use rustc_ast::util::parser::{PREC_POSTFIX, PREC_PREFIX};
 use rustc_data_structures::fx::FxIndexMap;
 use rustc_data_structures::graph::iterate::{CycleDetector, TriColorDepthFirstSearch};
@@ -28,7 +29,6 @@
     self, Binder, BoundVariableKind, Clause, 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};
 use rustc_trait_selection::infer::InferCtxtExt as _;
@@ -181,12 +181,12 @@ pub struct Dereferencing<'tcx> {
     possible_borrowers: Vec<(LocalDefId, PossibleBorrowerMap<'tcx, 'tcx>)>,
 
     // `IntoIterator` for arrays requires Rust 1.53.
-    msrv: Option<RustcVersion>,
+    msrv: Msrv,
 }
 
 impl<'tcx> Dereferencing<'tcx> {
     #[must_use]
-    pub fn new(msrv: Option<RustcVersion>) -> Self {
+    pub fn new(msrv: Msrv) -> Self {
         Self {
             msrv,
             ..Dereferencing::default()
@@ -286,26 +286,27 @@ 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, &mut self.possible_borrowers, expr, self.msrv);
+                let (position, adjustments) = walk_parents(cx, &mut self.possible_borrowers, expr, &self.msrv);
                 match kind {
                     RefOp::Deref => {
+                        let sub_ty = typeck.expr_ty(sub_expr);
                         if let Position::FieldAccess {
                             name,
                             of_union: false,
                         } = position
-                            && !ty_contains_field(typeck.expr_ty(sub_expr), name)
+                            && !ty_contains_field(sub_ty, name)
                         {
                             self.state = Some((
                                 State::ExplicitDerefField { name },
                                 StateData { span: expr.span, hir_id: expr.hir_id, position },
                             ));
-                        } else if position.is_deref_stable() {
+                        } else if position.is_deref_stable() && sub_ty.is_ref() {
                             self.state = Some((
                                 State::ExplicitDeref { mutability: None },
                                 StateData { span: expr.span, hir_id: expr.hir_id, position },
                             ));
                         }
-                    }
+                    },
                     RefOp::Method(target_mut)
                         if !is_lint_allowed(cx, EXPLICIT_DEREF_METHODS, expr.hir_id)
                             && position.lint_explicit_deref() =>
@@ -320,7 +321,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
                             StateData {
                                 span: expr.span,
                                 hir_id: expr.hir_id,
-                                position
+                                position,
                             },
                         ));
                     },
@@ -394,7 +395,11 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
                                     msg,
                                     snip_expr,
                                 }),
-                                StateData { span: expr.span, hir_id: expr.hir_id, position },
+                                StateData {
+                                    span: expr.span,
+                                    hir_id: expr.hir_id,
+                                    position,
+                                },
                             ));
                         } else if position.is_deref_stable()
                             // Auto-deref doesn't combine with other adjustments
@@ -406,7 +411,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
                                 StateData {
                                     span: expr.span,
                                     hir_id: expr.hir_id,
-                                    position
+                                    position,
                                 },
                             ));
                         }
@@ -698,7 +703,7 @@ fn walk_parents<'tcx>(
     cx: &LateContext<'tcx>,
     possible_borrowers: &mut Vec<(LocalDefId, PossibleBorrowerMap<'tcx, 'tcx>)>,
     e: &'tcx Expr<'_>,
-    msrv: Option<RustcVersion>,
+    msrv: &Msrv,
 ) -> (Position, &'tcx [Adjustment<'tcx>]) {
     let mut adjustments = [].as_slice();
     let mut precedence = 0i8;
@@ -862,7 +867,11 @@ fn walk_parents<'tcx>(
                             } && impl_ty.is_ref()
                             && let infcx = cx.tcx.infer_ctxt().build()
                             && infcx
-                                .type_implements_trait(trait_id, [impl_ty.into()].into_iter().chain(subs.iter().copied()), cx.param_env)
+                                .type_implements_trait(
+                                    trait_id,
+                                    [impl_ty.into()].into_iter().chain(subs.iter().copied()),
+                                    cx.param_env,
+                                )
                                 .must_apply_modulo_regions()
                         {
                             return Some(Position::MethodReceiverRefImpl)
@@ -1078,7 +1087,7 @@ fn needless_borrow_impl_arg_position<'tcx>(
     param_ty: ParamTy,
     mut expr: &Expr<'tcx>,
     precedence: i8,
-    msrv: Option<RustcVersion>,
+    msrv: &Msrv,
 ) -> Position {
     let destruct_trait_def_id = cx.tcx.lang_items().destruct_trait();
     let sized_trait_def_id = cx.tcx.lang_items().sized_trait();
@@ -1178,7 +1187,7 @@ fn needless_borrow_impl_arg_position<'tcx>(
                 && 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)
+                && !msrv.meets(msrvs::ARRAY_INTO_ITERATOR)
             {
                 return false;
             }
index d870e0ceef471ae2505aa6aafcdf1f483a2c4c6c..9e596ca8157eb93b58fc827d6c4d3eda261a116c 100644 (file)
@@ -14,8 +14,8 @@
 use rustc_middle::hir::nested_filter;
 use rustc_middle::traits::Reveal;
 use rustc_middle::ty::{
-    self, Binder, BoundConstness, Clause, GenericParamDefKind, ImplPolarity, ParamEnv, PredicateKind, TraitPredicate, TraitRef,
-    Ty, TyCtxt,
+    self, Binder, BoundConstness, Clause, GenericParamDefKind, ImplPolarity, ParamEnv, PredicateKind, TraitPredicate,
+    TraitRef, Ty, TyCtxt,
 };
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::source_map::Span;
index aee3d8c4f08527234f622a6ea81dc6f551a9920f..1f56d0118a404b50d88b938620c01b70fcc11212 100644 (file)
@@ -106,7 +106,9 @@ fn check_crate(&mut self, cx: &LateContext<'_>) {
 
     fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) {
         if let ItemKind::Use(path, UseKind::Single) = &item.kind {
-            self.check_res_emit(cx, &path.res, item.span);
+            for res in &path.res {
+                self.check_res_emit(cx, res, item.span);
+            }
         }
     }
 
index ae5f9424b2323b015f34a85547c880b5b387bb49..cdc23a4d22739ef79ebc7993a88ea902de69e617 100644 (file)
     /// ```
     #[clippy::version = "1.66.0"]
     pub UNNECESSARY_SAFETY_DOC,
-    style,
+    restriction,
     "`pub fn` or `pub trait` with `# Safety` docs"
 }
 
index f34cbee03558b74d0c4babaa3a7dab979d2b6ba9..3543910c3b55b470cb58db75a3e8c94cad7c0e5f 100644 (file)
@@ -11,7 +11,7 @@
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow};
 use rustc_middle::ty::binding::BindingMode;
-use rustc_middle::ty::{self, Ty, TypeVisitable};
+use rustc_middle::ty::{self, EarlyBinder, SubstsRef, Ty, TypeVisitable};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::symbol::sym;
 
@@ -125,7 +125,12 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
                     if let Some(mut snippet) = snippet_opt(cx, callee.span) {
                         if let Some(fn_mut_id) = cx.tcx.lang_items().fn_mut_trait()
                             && let args = cx.tcx.erase_late_bound_regions(substs.as_closure().sig()).inputs()
-                            && implements_trait(cx, callee_ty.peel_refs(), fn_mut_id, &args.iter().copied().map(Into::into).collect::<Vec<_>>())
+                            && implements_trait(
+                                   cx,
+                                   callee_ty.peel_refs(),
+                                   fn_mut_id,
+                                   &args.iter().copied().map(Into::into).collect::<Vec<_>>(),
+                               )
                             && path_to_local(callee).map_or(false, |l| local_used_after_expr(cx, l, expr))
                         {
                                 // Mutable closure is used after current expr; we cannot consume it.
@@ -152,7 +157,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
             if check_sig(cx, closure_ty, call_ty);
             then {
                 span_lint_and_then(cx, REDUNDANT_CLOSURE_FOR_METHOD_CALLS, expr.span, "redundant closure", |diag| {
-                    let name = get_ufcs_type_name(cx, method_def_id);
+                    let name = get_ufcs_type_name(cx, method_def_id, substs);
                     diag.span_suggestion(
                         expr.span,
                         "replace the closure with the method itself",
@@ -222,7 +227,7 @@ fn check_sig<'tcx>(cx: &LateContext<'tcx>, closure_ty: Ty<'tcx>, call_ty: Ty<'tc
     cx.tcx.erase_late_bound_regions(closure_sig) == cx.tcx.erase_late_bound_regions(call_sig)
 }
 
-fn get_ufcs_type_name(cx: &LateContext<'_>, method_def_id: DefId) -> String {
+fn get_ufcs_type_name<'tcx>(cx: &LateContext<'tcx>, method_def_id: DefId, substs: SubstsRef<'tcx>) -> String {
     let assoc_item = cx.tcx.associated_item(method_def_id);
     let def_id = assoc_item.container_id(cx.tcx);
     match assoc_item.container {
@@ -231,6 +236,15 @@ fn get_ufcs_type_name(cx: &LateContext<'_>, method_def_id: DefId) -> String {
             let ty = cx.tcx.type_of(def_id);
             match ty.kind() {
                 ty::Adt(adt, _) => cx.tcx.def_path_str(adt.did()),
+                ty::Array(..)
+                | ty::Dynamic(..)
+                | ty::Never
+                | ty::RawPtr(_)
+                | ty::Ref(..)
+                | ty::Slice(_)
+                | ty::Tuple(_) => {
+                    format!("<{}>", EarlyBinder(ty).subst(cx.tcx, substs))
+                },
                 _ => ty.to_string(),
             }
         },
index 407dd1b39575f4d63596ea341c8be18a2d7917f1..9c8b0d076dfd78ff353e09f68c6c437bf2d2eadb 100644 (file)
@@ -7,21 +7,34 @@
 
 declare_clippy_lint! {
     /// ### What it does
-    /// `exit()`  terminates the program and doesn't provide a
-    /// stack trace.
+    /// Detects calls to the `exit()` function which terminates the program.
     ///
     /// ### Why is this bad?
-    /// Ideally a program is terminated by finishing
+    /// Exit terminates the program at the location it is called. For unrecoverable
+    /// errors `panics` should be used to provide a stacktrace and potentualy other
+    /// information. A normal termination or one with an error code should happen in
     /// the main function.
     ///
     /// ### Example
-    /// ```ignore
+    /// ```
     /// std::process::exit(0)
     /// ```
+    ///
+    /// Use instead:
+    ///
+    /// ```ignore
+    /// // To provide a stacktrace and additional information
+    /// panic!("message");
+    ///
+    /// // or a main method with a return
+    /// fn main() -> Result<(), i32> {
+    ///     Ok(())
+    /// }
+    /// ```
     #[clippy::version = "1.41.0"]
     pub EXIT,
     restriction,
-    "`std::process::exit` is called, terminating the program"
+    "detects `std::process::exit` calls"
 }
 
 declare_lint_pass!(Exit => [EXIT]);
index f0fe845d330373ba036d55d70b6081047a3043ab..111b624f52994d747fc327b41830a4cbbba11ff8 100644 (file)
@@ -1,19 +1,22 @@
 use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then};
-use clippy_utils::macros::FormatParamKind::{Implicit, Named, Numbered, Starred};
+use clippy_utils::is_diag_trait_item;
+use clippy_utils::macros::FormatParamKind::{Implicit, Named, NamedInline, Numbered, Starred};
 use clippy_utils::macros::{
     is_format_macro, is_panic, root_macro_call, Count, FormatArg, FormatArgsExpn, FormatParam, FormatParamUsage,
 };
+use clippy_utils::msrvs::{self, Msrv};
 use clippy_utils::source::snippet_opt;
 use clippy_utils::ty::{implements_trait, is_type_diagnostic_item};
-use clippy_utils::{is_diag_trait_item, meets_msrv, msrvs};
 use if_chain::if_chain;
 use itertools::Itertools;
-use rustc_errors::Applicability;
+use rustc_errors::{
+    Applicability,
+    SuggestionStyle::{CompletelyHidden, ShowCode},
+};
 use rustc_hir::{Expr, ExprKind, HirId, QPath};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
 use rustc_middle::ty::adjustment::{Adjust, Adjustment};
 use rustc_middle::ty::Ty;
-use rustc_semver::RustcVersion;
 use rustc_session::{declare_tool_lint, impl_lint_pass};
 use rustc_span::def_id::DefId;
 use rustc_span::edition::Edition::Edition2021;
     /// format!("{var:.prec$}");
     /// ```
     ///
-    /// ### Known Problems
-    ///
-    /// There may be a false positive if the format string is expanded from certain proc macros:
-    ///
-    /// ```ignore
-    /// println!(indoc!("{}"), var);
+    /// If allow-mixed-uninlined-format-args is set to false in clippy.toml,
+    /// the following code will also trigger the lint:
+    /// ```rust
+    /// # let var = 42;
+    /// format!("{} {}", var, 1+2);
+    /// ```
+    /// Use instead:
+    /// ```rust
+    /// # let var = 42;
+    /// format!("{var} {}", 1+2);
     /// ```
     ///
+    /// ### Known Problems
+    ///
     /// If a format string contains a numbered argument that cannot be inlined
     /// nothing will be suggested, e.g. `println!("{0}={1}", var, 1+2)`.
     #[clippy::version = "1.65.0"]
     pub UNINLINED_FORMAT_ARGS,
-    pedantic,
+    style,
     "using non-inlined variables in `format!` calls"
 }
 
 ]);
 
 pub struct FormatArgs {
-    msrv: Option<RustcVersion>,
+    msrv: Msrv,
+    ignore_mixed: bool,
 }
 
 impl FormatArgs {
     #[must_use]
-    pub fn new(msrv: Option<RustcVersion>) -> Self {
-        Self { msrv }
+    pub fn new(msrv: Msrv, allow_mixed_uninlined_format_args: bool) -> Self {
+        Self {
+            msrv,
+            ignore_mixed: allow_mixed_uninlined_format_args,
+        }
     }
 }
 
@@ -188,8 +201,8 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
                 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);
             }
-            if meets_msrv(self.msrv, msrvs::FORMAT_ARGS_CAPTURE) {
-                check_uninlined_args(cx, &format_args, outermost_expn_data.call_site, macro_def_id);
+            if self.msrv.meets(msrvs::FORMAT_ARGS_CAPTURE) {
+                check_uninlined_args(cx, &format_args, outermost_expn_data.call_site, macro_def_id, self.ignore_mixed);
             }
         }
     }
@@ -267,7 +280,13 @@ fn check_unused_format_specifier(cx: &LateContext<'_>, arg: &FormatArg<'_>) {
     }
 }
 
-fn check_uninlined_args(cx: &LateContext<'_>, args: &FormatArgsExpn<'_>, call_site: Span, def_id: DefId) {
+fn check_uninlined_args(
+    cx: &LateContext<'_>,
+    args: &FormatArgsExpn<'_>,
+    call_site: Span,
+    def_id: DefId,
+    ignore_mixed: bool,
+) {
     if args.format_string.span.from_expansion() {
         return;
     }
@@ -282,14 +301,13 @@ fn check_uninlined_args(cx: &LateContext<'_>, args: &FormatArgsExpn<'_>, call_si
     // we cannot remove any other arguments in the format string,
     // because the index numbers might be wrong after inlining.
     // Example of an un-inlinable format:  print!("{}{1}", foo, 2)
-    if !args.params().all(|p| check_one_arg(args, &p, &mut fixes)) || fixes.is_empty() {
+    if !args.params().all(|p| check_one_arg(args, &p, &mut fixes, ignore_mixed)) || fixes.is_empty() {
         return;
     }
 
-    // Temporarily ignore multiline spans: https://github.com/rust-lang/rust/pull/102729#discussion_r988704308
-    if fixes.iter().any(|(span, _)| cx.sess().source_map().is_multiline(*span)) {
-        return;
-    }
+    // multiline span display suggestion is sometimes broken: https://github.com/rust-lang/rust/pull/102729#discussion_r988704308
+    // in those cases, make the code suggestion hidden
+    let multiline_fix = fixes.iter().any(|(span, _)| cx.sess().source_map().is_multiline(*span));
 
     span_lint_and_then(
         cx,
@@ -297,12 +315,22 @@ fn check_uninlined_args(cx: &LateContext<'_>, args: &FormatArgsExpn<'_>, call_si
         call_site,
         "variables can be used directly in the `format!` string",
         |diag| {
-            diag.multipart_suggestion("change this to", fixes, Applicability::MachineApplicable);
+            diag.multipart_suggestion_with_style(
+                "change this to",
+                fixes,
+                Applicability::MachineApplicable,
+                if multiline_fix { CompletelyHidden } else { ShowCode },
+            );
         },
     );
 }
 
-fn check_one_arg(args: &FormatArgsExpn<'_>, param: &FormatParam<'_>, fixes: &mut Vec<(Span, String)>) -> bool {
+fn check_one_arg(
+    args: &FormatArgsExpn<'_>,
+    param: &FormatParam<'_>,
+    fixes: &mut Vec<(Span, String)>,
+    ignore_mixed: bool,
+) -> bool {
     if matches!(param.kind, Implicit | Starred | Named(_) | Numbered)
         && let ExprKind::Path(QPath::Resolved(None, path)) = param.value.kind
         && let [segment] = path.segments
@@ -317,8 +345,10 @@ fn check_one_arg(args: &FormatArgsExpn<'_>, param: &FormatParam<'_>, fixes: &mut
         fixes.push((arg_span, String::new()));
         true  // successful inlining, continue checking
     } else {
-        // if we can't inline a numbered argument, we can't continue
-        param.kind != Numbered
+        // Do not continue inlining (return false) in case
+        // * if we can't inline a numbered argument, e.g. `print!("{0} ...", foo.bar, ...)`
+        // * if allow_mixed_uninlined_format_args is false and this arg hasn't been inlined already
+        param.kind != Numbered && (!ignore_mixed || matches!(param.kind, NamedInline(_)))
     }
 }
 
index 8b24a4962fb296ca4366c36e933206b987d1fa25..0634b2798fefee63669f0a2325e9e89b8332ca7a 100644 (file)
@@ -1,7 +1,8 @@
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::macros::span_is_local;
+use clippy_utils::msrvs::{self, Msrv};
+use clippy_utils::path_def_id;
 use clippy_utils::source::snippet_opt;
-use clippy_utils::{meets_msrv, msrvs, path_def_id};
 use rustc_errors::Applicability;
 use rustc_hir::intravisit::{walk_path, Visitor};
 use rustc_hir::{
@@ -10,7 +11,6 @@
 };
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::hir::nested_filter::OnlyBodies;
-use rustc_semver::RustcVersion;
 use rustc_session::{declare_tool_lint, impl_lint_pass};
 use rustc_span::symbol::{kw, sym};
 use rustc_span::{Span, Symbol};
 }
 
 pub struct FromOverInto {
-    msrv: Option<RustcVersion>,
+    msrv: Msrv,
 }
 
 impl FromOverInto {
     #[must_use]
-    pub fn new(msrv: Option<RustcVersion>) -> Self {
+    pub fn new(msrv: Msrv) -> Self {
         FromOverInto { msrv }
     }
 }
@@ -63,7 +63,7 @@ pub fn new(msrv: Option<RustcVersion>) -> Self {
 
 impl<'tcx> LateLintPass<'tcx> for FromOverInto {
     fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
-        if !meets_msrv(self.msrv, msrvs::RE_REBALANCING_COHERENCE) || !span_is_local(item.span) {
+        if !self.msrv.meets(msrvs::RE_REBALANCING_COHERENCE) || !span_is_local(item.span) {
             return;
         }
 
@@ -126,7 +126,7 @@ fn nested_visit_map(&mut self) -> Self::Map {
         self.cx.tcx.hir()
     }
 
-    fn visit_path(&mut self, path: &'tcx Path<'tcx>, _id: HirId) {
+    fn visit_path(&mut self, path: &Path<'tcx>, _id: HirId) {
         for segment in path.segments {
             match segment.ident.name {
                 kw::SelfLower => self.lower.push(segment.ident.span),
diff --git a/src/tools/clippy/clippy_lints/src/functions/misnamed_getters.rs b/src/tools/clippy/clippy_lints/src/functions/misnamed_getters.rs
new file mode 100644 (file)
index 0000000..27acad4
--- /dev/null
@@ -0,0 +1,125 @@
+use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::source::snippet;
+use rustc_errors::Applicability;
+use rustc_hir::{intravisit::FnKind, Body, ExprKind, FnDecl, HirId, ImplicitSelfKind, Unsafety};
+use rustc_lint::LateContext;
+use rustc_middle::ty;
+use rustc_span::Span;
+
+use std::iter;
+
+use super::MISNAMED_GETTERS;
+
+pub fn check_fn(
+    cx: &LateContext<'_>,
+    kind: FnKind<'_>,
+    decl: &FnDecl<'_>,
+    body: &Body<'_>,
+    span: Span,
+    _hir_id: HirId,
+) {
+    let FnKind::Method(ref ident, sig) = kind else {
+            return;
+        };
+
+    // Takes only &(mut) self
+    if decl.inputs.len() != 1 {
+        return;
+    }
+
+    let name = ident.name.as_str();
+
+    let name = match decl.implicit_self {
+        ImplicitSelfKind::MutRef => {
+            let Some(name) = name.strip_suffix("_mut") else {
+                    return;
+                };
+            name
+        },
+        ImplicitSelfKind::Imm | ImplicitSelfKind::Mut | ImplicitSelfKind::ImmRef => name,
+        ImplicitSelfKind::None => return,
+    };
+
+    let name = if sig.header.unsafety == Unsafety::Unsafe {
+        name.strip_suffix("_unchecked").unwrap_or(name)
+    } else {
+        name
+    };
+
+    // Body must be &(mut) <self_data>.name
+    // self_data is not neccessarilly self, to also lint sub-getters, etc…
+
+    let block_expr = if_chain! {
+        if let ExprKind::Block(block,_) = body.value.kind;
+        if block.stmts.is_empty();
+        if let Some(block_expr) = block.expr;
+        then {
+            block_expr
+        } else {
+            return;
+        }
+    };
+    let expr_span = block_expr.span;
+
+    // Accept &<expr>, &mut <expr> and <expr>
+    let expr = if let ExprKind::AddrOf(_, _, tmp) = block_expr.kind {
+        tmp
+    } else {
+        block_expr
+    };
+    let (self_data, used_ident) = if_chain! {
+        if let ExprKind::Field(self_data, ident) = expr.kind;
+        if ident.name.as_str() != name;
+        then {
+            (self_data, ident)
+        } else {
+            return;
+        }
+    };
+
+    let mut used_field = None;
+    let mut correct_field = None;
+    let typeck_results = cx.typeck_results();
+    for adjusted_type in iter::once(typeck_results.expr_ty(self_data))
+        .chain(typeck_results.expr_adjustments(self_data).iter().map(|adj| adj.target))
+    {
+        let ty::Adt(def,_) = adjusted_type.kind() else {
+            continue;
+        };
+
+        for f in def.all_fields() {
+            if f.name.as_str() == name {
+                correct_field = Some(f);
+            }
+            if f.name == used_ident.name {
+                used_field = Some(f);
+            }
+        }
+    }
+
+    let Some(used_field) = used_field else {
+        // Can happen if the field access is a tuple. We don't lint those because the getter name could not start with a number.
+        return;
+    };
+
+    let Some(correct_field) = correct_field else {
+        // There is no field corresponding to the getter name.
+        // FIXME: This can be a false positive if the correct field is reachable trought deeper autodereferences than used_field is
+        return;
+    };
+
+    if cx.tcx.type_of(used_field.did) == cx.tcx.type_of(correct_field.did) {
+        let left_span = block_expr.span.until(used_ident.span);
+        let snippet = snippet(cx, left_span, "..");
+        let sugg = format!("{snippet}{name}");
+        span_lint_and_then(
+            cx,
+            MISNAMED_GETTERS,
+            span,
+            "getter function appears to return the wrong field",
+            |diag| {
+                diag.span_suggestion(expr_span, "consider using", sugg, Applicability::MaybeIncorrect);
+            },
+        );
+    }
+}
index ae0e08334463803dbfce17b707bdbbab3fda0773..91e6ffe6447909d610bd14774b269c301c1eb0cf 100644 (file)
@@ -1,3 +1,4 @@
+mod misnamed_getters;
 mod must_use;
 mod not_unsafe_ptr_arg_deref;
 mod result;
     "function returning `Result` with large `Err` type"
 }
 
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for getter methods that return a field that doesn't correspond
+    /// to the name of the method, when there is a field's whose name matches that of the method.
+    ///
+    /// ### Why is this bad?
+    /// It is most likely that such a  method is a bug caused by a typo or by copy-pasting.
+    ///
+    /// ### Example
+
+    /// ```rust
+    /// struct A {
+    ///     a: String,
+    ///     b: String,
+    /// }
+    ///
+    /// impl A {
+    ///     fn a(&self) -> &str{
+    ///         &self.b
+    ///     }
+    /// }
+
+    /// ```
+    /// Use instead:
+    /// ```rust
+    /// struct A {
+    ///     a: String,
+    ///     b: String,
+    /// }
+    ///
+    /// impl A {
+    ///     fn a(&self) -> &str{
+    ///         &self.a
+    ///     }
+    /// }
+    /// ```
+    #[clippy::version = "1.67.0"]
+    pub MISNAMED_GETTERS,
+    suspicious,
+    "getter method returning the wrong field"
+}
+
 #[derive(Copy, Clone)]
 pub struct Functions {
     too_many_arguments_threshold: u64,
@@ -286,6 +329,7 @@ pub fn new(too_many_arguments_threshold: u64, too_many_lines_threshold: u64, lar
     MUST_USE_CANDIDATE,
     RESULT_UNIT_ERR,
     RESULT_LARGE_ERR,
+    MISNAMED_GETTERS,
 ]);
 
 impl<'tcx> LateLintPass<'tcx> for Functions {
@@ -301,6 +345,7 @@ fn check_fn(
         too_many_arguments::check_fn(cx, kind, decl, span, hir_id, self.too_many_arguments_threshold);
         too_many_lines::check_fn(cx, kind, span, body, self.too_many_lines_threshold);
         not_unsafe_ptr_arg_deref::check_fn(cx, kind, decl, body, hir_id);
+        misnamed_getters::check_fn(cx, kind, decl, body, span, hir_id);
     }
 
     fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) {
index f7e30b051a694a84d6be001e103f067a804d58b7..23da145d038257be75f38c88c8247ac55aaa169a 100644 (file)
@@ -94,7 +94,9 @@ fn check_result_large_err<'tcx>(cx: &LateContext<'tcx>, err_ty: Ty<'tcx>, hir_ty
         if let hir::ItemKind::Enum(ref def, _) = item.kind;
         then {
             let variants_size = AdtVariantInfo::new(cx, *adt, subst);
-            if variants_size[0].size >= large_err_threshold {
+            if let Some((first_variant, variants)) = variants_size.split_first()
+                && first_variant.size >= large_err_threshold
+            {
                 span_lint_and_then(
                     cx,
                     RESULT_LARGE_ERR,
@@ -102,11 +104,11 @@ fn check_result_large_err<'tcx>(cx: &LateContext<'tcx>, err_ty: Ty<'tcx>, hir_ty
                     "the `Err`-variant returned from this function is very large",
                     |diag| {
                         diag.span_label(
-                            def.variants[variants_size[0].ind].span,
+                            def.variants[first_variant.ind].span,
                             format!("the largest variant contains at least {} bytes", variants_size[0].size),
                         );
 
-                        for variant in &variants_size[1..] {
+                        for variant in variants {
                             if variant.size >= large_err_threshold {
                                 let variant_def = &def.variants[variant.ind];
                                 diag.span_label(
index a9425a40f885ea192bf50e263c900b44d09d77b4..61934a9142633003f805f421ea4f9855451e76f3 100644 (file)
@@ -91,7 +91,9 @@ fn check_fn(
                                 infcx
                                     .err_ctxt()
                                     .maybe_note_obligation_cause_for_async_await(db, &obligation);
-                                if let PredicateKind::Clause(Clause::Trait(trait_pred)) = obligation.predicate.kind().skip_binder() {
+                                if let PredicateKind::Clause(Clause::Trait(trait_pred)) =
+                                    obligation.predicate.kind().skip_binder()
+                                {
                                     db.note(&format!(
                                         "`{}` doesn't implement `{}`",
                                         trait_pred.self_ty(),
index 0d6718c168a5c9da12865ee7633dc5078ad7e33a..9cadaaa493e465c0b4032f6adec143c752eb5681 100644 (file)
@@ -1,14 +1,12 @@
 use clippy_utils::diagnostics::span_lint_and_help;
 use clippy_utils::eager_or_lazy::switch_to_eager_eval;
+use clippy_utils::msrvs::{self, Msrv};
 use clippy_utils::source::snippet_with_macro_callsite;
-use clippy_utils::{
-    contains_return, higher, is_else_clause, is_res_lang_ctor, meets_msrv, msrvs, path_res, peel_blocks,
-};
+use clippy_utils::{contains_return, higher, is_else_clause, is_res_lang_ctor, path_res, peel_blocks};
 use rustc_hir::LangItem::{OptionNone, OptionSome};
 use rustc_hir::{Expr, ExprKind, Stmt, StmtKind};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
 use rustc_middle::lint::in_external_macro;
-use rustc_semver::RustcVersion;
 use rustc_session::{declare_tool_lint, impl_lint_pass};
 
 declare_clippy_lint! {
 }
 
 pub struct IfThenSomeElseNone {
-    msrv: Option<RustcVersion>,
+    msrv: Msrv,
 }
 
 impl IfThenSomeElseNone {
     #[must_use]
-    pub fn new(msrv: Option<RustcVersion>) -> Self {
+    pub fn new(msrv: Msrv) -> Self {
         Self { msrv }
     }
 }
@@ -61,7 +59,7 @@ pub fn new(msrv: Option<RustcVersion>) -> Self {
 
 impl<'tcx> LateLintPass<'tcx> for IfThenSomeElseNone {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
-        if !meets_msrv(self.msrv, msrvs::BOOL_THEN) {
+        if !self.msrv.meets(msrvs::BOOL_THEN) {
             return;
         }
 
@@ -94,7 +92,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
             } else {
                 format!("{{ /* snippet */ {arg_snip} }}")
             };
-            let method_name = if switch_to_eager_eval(cx, expr) && meets_msrv(self.msrv, msrvs::BOOL_THEN_SOME) {
+            let method_name = if switch_to_eager_eval(cx, expr) && self.msrv.meets(msrvs::BOOL_THEN_SOME) {
                 "then_some"
             } else {
                 method_body.insert_str(0, "|| ");
index 0d5099bde6de015b5aa069e5bdeb6611afd9d471..cf35b1f175c602fd4fa70e677c1b202233968811 100644 (file)
@@ -1,8 +1,9 @@
 use clippy_utils::consts::{constant, Constant};
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::higher::IfLet;
+use clippy_utils::msrvs::{self, Msrv};
 use clippy_utils::ty::is_copy;
-use clippy_utils::{is_expn_of, is_lint_allowed, meets_msrv, msrvs, path_to_local};
+use clippy_utils::{is_expn_of, is_lint_allowed, path_to_local};
 use if_chain::if_chain;
 use rustc_data_structures::fx::{FxHashSet, FxIndexMap};
 use rustc_errors::Applicability;
@@ -11,7 +12,6 @@
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::hir::nested_filter;
 use rustc_middle::ty;
-use rustc_semver::RustcVersion;
 use rustc_session::{declare_tool_lint, impl_lint_pass};
 use rustc_span::{symbol::Ident, Span};
 
     /// ```
     #[clippy::version = "1.59.0"]
     pub INDEX_REFUTABLE_SLICE,
-    nursery,
+    pedantic,
     "avoid indexing on slices which could be destructed"
 }
 
-#[derive(Copy, Clone)]
 pub struct IndexRefutableSlice {
     max_suggested_slice: u64,
-    msrv: Option<RustcVersion>,
+    msrv: Msrv,
 }
 
 impl IndexRefutableSlice {
-    pub fn new(max_suggested_slice_pattern_length: u64, msrv: Option<RustcVersion>) -> Self {
+    pub fn new(max_suggested_slice_pattern_length: u64, msrv: Msrv) -> Self {
         Self {
             max_suggested_slice: max_suggested_slice_pattern_length,
             msrv,
@@ -74,7 +73,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
             if !expr.span.from_expansion() || is_expn_of(expr.span, "if_chain").is_some();
             if let Some(IfLet {let_pat, if_then, ..}) = IfLet::hir(cx, expr);
             if !is_lint_allowed(cx, INDEX_REFUTABLE_SLICE, expr.hir_id);
-            if meets_msrv(self.msrv, msrvs::SLICE_PATTERNS);
+            if self.msrv.meets(msrvs::SLICE_PATTERNS);
 
             let found_slices = find_slice_values(cx, let_pat);
             if !found_slices.is_empty();
index 60754b224fc840a8f21ff7b153f028f3b5f48ee0..dd1b23e7d9d29f19a513b36efbc1468e690907b0 100644 (file)
@@ -1,13 +1,11 @@
-use clippy_utils::{
-    diagnostics::{self, span_lint_and_sugg},
-    meets_msrv, msrvs, source,
-    sugg::Sugg,
-    ty,
-};
+use clippy_utils::diagnostics::{self, span_lint_and_sugg};
+use clippy_utils::msrvs::{self, Msrv};
+use clippy_utils::source;
+use clippy_utils::sugg::Sugg;
+use clippy_utils::ty;
 use rustc_errors::Applicability;
 use rustc_hir::{BinOpKind, Expr, ExprKind};
 use rustc_lint::{LateContext, LateLintPass};
-use rustc_semver::RustcVersion;
 use rustc_session::{declare_tool_lint, impl_lint_pass};
 use rustc_span::{source_map::Spanned, sym};
 
 }
 
 pub struct InstantSubtraction {
-    msrv: Option<RustcVersion>,
+    msrv: Msrv,
 }
 
 impl InstantSubtraction {
     #[must_use]
-    pub fn new(msrv: Option<RustcVersion>) -> Self {
+    pub fn new(msrv: Msrv) -> Self {
         Self { msrv }
     }
 }
@@ -101,7 +99,7 @@ fn check_expr(&mut self, cx: &LateContext<'_>, expr: &'_ Expr<'_>) {
                 } else {
                     if_chain! {
                         if !expr.span.from_expansion();
-                        if meets_msrv(self.msrv, msrvs::TRY_FROM);
+                        if self.msrv.meets(msrvs::TRY_FROM);
 
                         if is_an_instant(cx, lhs);
                         if is_a_duration(cx, rhs);
index 601990cd6a3169776a4e3f0cd8005d07196d18d0..7b17d8a156d5af6ddb3b9417b7990e65d2a3d5ee 100644 (file)
 use std::io;
 use std::path::PathBuf;
 
-use clippy_utils::parse_msrv;
+use clippy_utils::msrvs::Msrv;
 use rustc_data_structures::fx::FxHashSet;
 use rustc_lint::{Lint, LintId};
-use rustc_semver::RustcVersion;
 use rustc_session::Session;
 
 #[cfg(feature = "internal")]
 /// Used in `./src/driver.rs`.
 pub fn register_pre_expansion_lints(store: &mut rustc_lint::LintStore, sess: &Session, conf: &Conf) {
     // NOTE: Do not add any more pre-expansion passes. These should be removed eventually.
+    let msrv = Msrv::read(&conf.msrv, sess);
+    let msrv = move || msrv.clone();
 
-    let msrv = conf.msrv.as_ref().and_then(|s| {
-        parse_msrv(s, None, None).or_else(|| {
-            sess.err(format!(
-                "error reading Clippy's configuration file. `{s}` is not a valid Rust version"
-            ));
-            None
-        })
-    });
-
-    store.register_pre_expansion_pass(move || Box::new(attrs::EarlyAttributes { msrv }));
-}
-
-fn read_msrv(conf: &Conf, sess: &Session) -> Option<RustcVersion> {
-    let cargo_msrv = std::env::var("CARGO_PKG_RUST_VERSION")
-        .ok()
-        .and_then(|v| parse_msrv(&v, None, None));
-    let clippy_msrv = conf.msrv.as_ref().and_then(|s| {
-        parse_msrv(s, None, None).or_else(|| {
-            sess.err(format!(
-                "error reading Clippy's configuration file. `{s}` is not a valid Rust version"
-            ));
-            None
-        })
-    });
-
-    if let Some(cargo_msrv) = cargo_msrv {
-        if let Some(clippy_msrv) = clippy_msrv {
-            // if both files have an msrv, let's compare them and emit a warning if they differ
-            if clippy_msrv != cargo_msrv {
-                sess.warn(format!(
-                    "the MSRV in `clippy.toml` and `Cargo.toml` differ; using `{clippy_msrv}` from `clippy.toml`"
-                ));
-            }
-
-            Some(clippy_msrv)
-        } else {
-            Some(cargo_msrv)
-        }
-    } else {
-        clippy_msrv
-    }
+    store.register_pre_expansion_pass(move || Box::new(attrs::EarlyAttributes { msrv: msrv() }));
 }
 
 #[doc(hidden)]
@@ -595,43 +556,44 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     store.register_late_pass(|_| Box::new(non_octal_unix_permissions::NonOctalUnixPermissions));
     store.register_early_pass(|| Box::new(unnecessary_self_imports::UnnecessarySelfImports));
 
-    let msrv = read_msrv(conf, sess);
+    let msrv = Msrv::read(&conf.msrv, sess);
+    let msrv = move || msrv.clone();
     let avoid_breaking_exported_api = conf.avoid_breaking_exported_api;
     let allow_expect_in_tests = conf.allow_expect_in_tests;
     let allow_unwrap_in_tests = conf.allow_unwrap_in_tests;
-    store.register_late_pass(move |_| Box::new(approx_const::ApproxConstant::new(msrv)));
+    store.register_late_pass(move |_| Box::new(approx_const::ApproxConstant::new(msrv())));
     store.register_late_pass(move |_| {
         Box::new(methods::Methods::new(
             avoid_breaking_exported_api,
-            msrv,
+            msrv(),
             allow_expect_in_tests,
             allow_unwrap_in_tests,
         ))
     });
-    store.register_late_pass(move |_| Box::new(matches::Matches::new(msrv)));
+    store.register_late_pass(move |_| Box::new(matches::Matches::new(msrv())));
     let matches_for_let_else = conf.matches_for_let_else;
-    store.register_late_pass(move |_| Box::new(manual_let_else::ManualLetElse::new(msrv, matches_for_let_else)));
-    store.register_early_pass(move || Box::new(manual_non_exhaustive::ManualNonExhaustiveStruct::new(msrv)));
-    store.register_late_pass(move |_| Box::new(manual_non_exhaustive::ManualNonExhaustiveEnum::new(msrv)));
-    store.register_late_pass(move |_| Box::new(manual_strip::ManualStrip::new(msrv)));
-    store.register_early_pass(move || Box::new(redundant_static_lifetimes::RedundantStaticLifetimes::new(msrv)));
-    store.register_early_pass(move || Box::new(redundant_field_names::RedundantFieldNames::new(msrv)));
-    store.register_late_pass(move |_| Box::new(checked_conversions::CheckedConversions::new(msrv)));
-    store.register_late_pass(move |_| Box::new(mem_replace::MemReplace::new(msrv)));
-    store.register_late_pass(move |_| Box::new(ranges::Ranges::new(msrv)));
-    store.register_late_pass(move |_| Box::new(from_over_into::FromOverInto::new(msrv)));
-    store.register_late_pass(move |_| Box::new(use_self::UseSelf::new(msrv)));
-    store.register_late_pass(move |_| Box::new(missing_const_for_fn::MissingConstForFn::new(msrv)));
+    store.register_late_pass(move |_| Box::new(manual_let_else::ManualLetElse::new(msrv(), matches_for_let_else)));
+    store.register_early_pass(move || Box::new(manual_non_exhaustive::ManualNonExhaustiveStruct::new(msrv())));
+    store.register_late_pass(move |_| Box::new(manual_non_exhaustive::ManualNonExhaustiveEnum::new(msrv())));
+    store.register_late_pass(move |_| Box::new(manual_strip::ManualStrip::new(msrv())));
+    store.register_early_pass(move || Box::new(redundant_static_lifetimes::RedundantStaticLifetimes::new(msrv())));
+    store.register_early_pass(move || Box::new(redundant_field_names::RedundantFieldNames::new(msrv())));
+    store.register_late_pass(move |_| Box::new(checked_conversions::CheckedConversions::new(msrv())));
+    store.register_late_pass(move |_| Box::new(mem_replace::MemReplace::new(msrv())));
+    store.register_late_pass(move |_| Box::new(ranges::Ranges::new(msrv())));
+    store.register_late_pass(move |_| Box::new(from_over_into::FromOverInto::new(msrv())));
+    store.register_late_pass(move |_| Box::new(use_self::UseSelf::new(msrv())));
+    store.register_late_pass(move |_| Box::new(missing_const_for_fn::MissingConstForFn::new(msrv())));
     store.register_late_pass(move |_| Box::new(needless_question_mark::NeedlessQuestionMark));
-    store.register_late_pass(move |_| Box::new(casts::Casts::new(msrv)));
-    store.register_early_pass(move || Box::new(unnested_or_patterns::UnnestedOrPatterns::new(msrv)));
+    store.register_late_pass(move |_| Box::new(casts::Casts::new(msrv())));
+    store.register_early_pass(move || Box::new(unnested_or_patterns::UnnestedOrPatterns::new(msrv())));
     store.register_late_pass(|_| Box::new(size_of_in_element_count::SizeOfInElementCount));
     store.register_late_pass(|_| Box::new(same_name_method::SameNameMethod));
     let max_suggested_slice_pattern_length = conf.max_suggested_slice_pattern_length;
     store.register_late_pass(move |_| {
         Box::new(index_refutable_slice::IndexRefutableSlice::new(
             max_suggested_slice_pattern_length,
-            msrv,
+            msrv(),
         ))
     });
     store.register_late_pass(|_| Box::<shadow::Shadow>::default());
@@ -648,7 +610,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     store.register_late_pass(|_| Box::new(borrow_deref_ref::BorrowDerefRef));
     store.register_late_pass(|_| Box::new(no_effect::NoEffect));
     store.register_late_pass(|_| Box::new(temporary_assignment::TemporaryAssignment));
-    store.register_late_pass(move |_| Box::new(transmute::Transmute::new(msrv)));
+    store.register_late_pass(move |_| Box::new(transmute::Transmute::new(msrv())));
     let cognitive_complexity_threshold = conf.cognitive_complexity_threshold;
     store.register_late_pass(move |_| {
         Box::new(cognitive_complexity::CognitiveComplexity::new(
@@ -806,7 +768,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     store.register_late_pass(move |_| Box::new(wildcard_imports::WildcardImports::new(warn_on_all_wildcard_imports)));
     store.register_late_pass(|_| Box::<redundant_pub_crate::RedundantPubCrate>::default());
     store.register_late_pass(|_| Box::new(unnamed_address::UnnamedAddress));
-    store.register_late_pass(move |_| Box::new(dereference::Dereferencing::new(msrv)));
+    store.register_late_pass(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));
@@ -840,7 +802,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     store.register_late_pass(|_| Box::<vec_init_then_push::VecInitThenPush>::default());
     store.register_late_pass(|_| Box::new(redundant_slicing::RedundantSlicing));
     store.register_late_pass(|_| Box::new(from_str_radix_10::FromStrRadix10));
-    store.register_late_pass(move |_| Box::new(if_then_some_else_none::IfThenSomeElseNone::new(msrv)));
+    store.register_late_pass(move |_| Box::new(if_then_some_else_none::IfThenSomeElseNone::new(msrv())));
     store.register_late_pass(|_| Box::new(bool_assert_comparison::BoolAssertComparison));
     store.register_early_pass(move || Box::new(module_style::ModStyle));
     store.register_late_pass(|_| Box::new(unused_async::UnusedAsync));
@@ -865,14 +827,15 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         ))
     });
     store.register_late_pass(move |_| Box::new(undocumented_unsafe_blocks::UndocumentedUnsafeBlocks));
-    store.register_late_pass(move |_| Box::new(format_args::FormatArgs::new(msrv)));
+    let allow_mixed_uninlined = conf.allow_mixed_uninlined_format_args;
+    store.register_late_pass(move |_| Box::new(format_args::FormatArgs::new(msrv(), allow_mixed_uninlined)));
     store.register_late_pass(|_| Box::new(trailing_empty_array::TrailingEmptyArray));
     store.register_early_pass(|| Box::new(octal_escapes::OctalEscapes));
     store.register_late_pass(|_| Box::new(needless_late_init::NeedlessLateInit));
     store.register_late_pass(|_| Box::new(return_self_not_must_use::ReturnSelfNotMustUse));
     store.register_late_pass(|_| Box::new(init_numbered_fields::NumberedFields));
     store.register_early_pass(|| Box::new(single_char_lifetime_names::SingleCharLifetimeNames));
-    store.register_late_pass(move |_| Box::new(manual_bits::ManualBits::new(msrv)));
+    store.register_late_pass(move |_| Box::new(manual_bits::ManualBits::new(msrv())));
     store.register_late_pass(|_| Box::new(default_union_representation::DefaultUnionRepresentation));
     store.register_late_pass(|_| Box::<only_used_in_recursion::OnlyUsedInRecursion>::default());
     let allow_dbg_in_tests = conf.allow_dbg_in_tests;
@@ -896,20 +859,20 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     store.register_late_pass(|_| Box::new(rc_clone_in_vec_init::RcCloneInVecInit));
     store.register_early_pass(|| Box::<duplicate_mod::DuplicateMod>::default());
     store.register_early_pass(|| Box::new(unused_rounding::UnusedRounding));
-    store.register_early_pass(move || Box::new(almost_complete_letter_range::AlmostCompleteLetterRange::new(msrv)));
+    store.register_early_pass(move || Box::new(almost_complete_letter_range::AlmostCompleteLetterRange::new(msrv())));
     store.register_late_pass(|_| Box::new(swap_ptr_to_ref::SwapPtrToRef));
     store.register_late_pass(|_| Box::new(mismatching_type_param_order::TypeParamMismatch));
     store.register_late_pass(|_| Box::new(read_zero_byte_vec::ReadZeroByteVec));
     store.register_late_pass(|_| Box::new(default_instead_of_iter_empty::DefaultIterEmpty));
-    store.register_late_pass(move |_| Box::new(manual_rem_euclid::ManualRemEuclid::new(msrv)));
-    store.register_late_pass(move |_| Box::new(manual_retain::ManualRetain::new(msrv)));
+    store.register_late_pass(move |_| Box::new(manual_rem_euclid::ManualRemEuclid::new(msrv())));
+    store.register_late_pass(move |_| Box::new(manual_retain::ManualRetain::new(msrv())));
     let verbose_bit_mask_threshold = conf.verbose_bit_mask_threshold;
     store.register_late_pass(move |_| Box::new(operators::Operators::new(verbose_bit_mask_threshold)));
     store.register_late_pass(|_| Box::new(invalid_utf8_in_unchecked::InvalidUtf8InUnchecked));
     store.register_late_pass(|_| Box::<std_instead_of_core::StdReexports>::default());
-    store.register_late_pass(move |_| Box::new(instant_subtraction::InstantSubtraction::new(msrv)));
+    store.register_late_pass(move |_| Box::new(instant_subtraction::InstantSubtraction::new(msrv())));
     store.register_late_pass(|_| Box::new(partialeq_to_none::PartialeqToNone));
-    store.register_late_pass(move |_| Box::new(manual_clamp::ManualClamp::new(msrv)));
+    store.register_late_pass(move |_| Box::new(manual_clamp::ManualClamp::new(msrv())));
     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));
@@ -920,7 +883,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     store.register_late_pass(|_| Box::new(missing_trait_methods::MissingTraitMethods));
     store.register_late_pass(|_| Box::new(from_raw_with_void_ptr::FromRawWithVoidPtr));
     store.register_late_pass(|_| Box::new(suspicious_xor_used_as_pow::ConfusingXorAndPow));
-    store.register_late_pass(move |_| Box::new(manual_is_ascii_check::ManualIsAsciiCheck::new(msrv)));
+    store.register_late_pass(move |_| Box::new(manual_is_ascii_check::ManualIsAsciiCheck::new(msrv())));
     // add lints here, do not remove this comment, it's used in `new_lint`
 }
 
index 220941dcd5dbf6c4b0696b6c4d7fef98aa578a4f..7cf1a6b8084a613b9053e2c1fe18bd2498f590d8 100644 (file)
@@ -3,7 +3,7 @@
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_hir::intravisit::nested_filter::{self as hir_nested_filter, NestedFilter};
 use rustc_hir::intravisit::{
-    walk_fn_decl, walk_generic_param, walk_generics, walk_impl_item_ref, walk_item, walk_param_bound,
+    walk_fn_decl, walk_generic_arg, walk_generic_param, walk_generics, walk_impl_item_ref, walk_item, walk_param_bound,
     walk_poly_trait_ref, walk_trait_ref, walk_ty, Visitor,
 };
 use rustc_hir::lang_items;
@@ -481,7 +481,7 @@ fn visit_ty(&mut self, ty: &'tcx Ty<'_>) {
                 sub_visitor.visit_fn_decl(decl);
                 self.nested_elision_site_lts.append(&mut sub_visitor.all_lts());
             },
-            TyKind::TraitObject(bounds, ref lt, _) => {
+            TyKind::TraitObject(bounds, lt, _) => {
                 if !lt.is_elided() {
                     self.unelided_trait_object_lifetime = true;
                 }
@@ -497,14 +497,7 @@ fn visit_generic_arg(&mut self, generic_arg: &'tcx GenericArg<'tcx>) {
         if let GenericArg::Lifetime(l) = generic_arg && let LifetimeName::Param(def_id) = l.res {
             self.lifetime_generic_arg_spans.entry(def_id).or_insert(l.ident.span);
         }
-        // Replace with `walk_generic_arg` if/when https://github.com/rust-lang/rust/pull/103692 lands.
-        // walk_generic_arg(self, generic_arg);
-        match generic_arg {
-            GenericArg::Lifetime(lt) => self.visit_lifetime(lt),
-            GenericArg::Type(ty) => self.visit_ty(ty),
-            GenericArg::Const(ct) => self.visit_anon_const(&ct.value),
-            GenericArg::Infer(inf) => self.visit_infer(inf),
-        }
+        walk_generic_arg(self, generic_arg);
     }
 }
 
index 594f6af76b3d874f339203d06ce5c066e9bab9e8..e2e6a87a30151472b7bc93e250f556275641f441 100644 (file)
@@ -94,7 +94,10 @@ fn check_item(&mut self, cx: &LateContext<'_>, item: &hir::Item<'_>) {
             let hir_id = item.hir_id();
             let attrs = cx.tcx.hir().attrs(hir_id);
             if let Some(mac_attr) = attrs.iter().find(|attr| attr.has_name(sym::macro_use));
-            if let Res::Def(DefKind::Mod, id) = path.res;
+            if let Some(id) = path.res.iter().find_map(|res| match res {
+                Res::Def(DefKind::Mod, id) => Some(id),
+                _ => None,
+            });
             if !id.is_local();
             then {
                 for kid in cx.tcx.module_children(id).iter() {
index 6655c92b1da8da05a2f2f983bbe9fd8e28eaf439..462d73cf0b974ff8675b306763e8c5108446cb1f 100644 (file)
@@ -1,12 +1,12 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::get_parent_expr;
+use clippy_utils::msrvs::{self, Msrv};
 use clippy_utils::source::snippet_with_applicability;
-use clippy_utils::{get_parent_expr, meets_msrv, msrvs};
 use rustc_ast::ast::LitKind;
 use rustc_errors::Applicability;
 use rustc_hir::{BinOpKind, Expr, ExprKind, GenericArg, QPath};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty::{self, Ty};
-use rustc_semver::RustcVersion;
 use rustc_session::{declare_tool_lint, impl_lint_pass};
 use rustc_span::sym;
 
 
 #[derive(Clone)]
 pub struct ManualBits {
-    msrv: Option<RustcVersion>,
+    msrv: Msrv,
 }
 
 impl ManualBits {
     #[must_use]
-    pub fn new(msrv: Option<RustcVersion>) -> Self {
+    pub fn new(msrv: Msrv) -> Self {
         Self { msrv }
     }
 }
@@ -48,7 +48,7 @@ pub fn new(msrv: Option<RustcVersion>) -> Self {
 
 impl<'tcx> LateLintPass<'tcx> for ManualBits {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
-        if !meets_msrv(self.msrv, msrvs::MANUAL_BITS) {
+        if !self.msrv.meets(msrvs::MANUAL_BITS) {
             return;
         }
 
index 02dc8755dd61c9e86f23bbe209066680d964d5f0..bb6d628af3b5061f35c3a19e7df8498481c8ad5e 100644 (file)
@@ -1,28 +1,25 @@
+use clippy_utils::diagnostics::{span_lint_and_then, span_lint_hir_and_then};
+use clippy_utils::higher::If;
+use clippy_utils::msrvs::{self, Msrv};
+use clippy_utils::sugg::Sugg;
+use clippy_utils::ty::implements_trait;
+use clippy_utils::visitors::is_const_evaluatable;
+use clippy_utils::MaybePath;
+use clippy_utils::{
+    eq_expr_value, is_diag_trait_item, is_trait_method, path_res, path_to_local_id, peel_blocks, peel_blocks_with_stmt,
+};
 use itertools::Itertools;
+use rustc_errors::Applicability;
 use rustc_errors::Diagnostic;
 use rustc_hir::{
     def::Res, Arm, BinOpKind, Block, Expr, ExprKind, Guard, HirId, PatKind, PathSegment, PrimTy, QPath, StmtKind,
 };
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty::Ty;
-use rustc_semver::RustcVersion;
 use rustc_session::{declare_tool_lint, impl_lint_pass};
 use rustc_span::{symbol::sym, Span};
 use std::ops::Deref;
 
-use clippy_utils::{
-    diagnostics::{span_lint_and_then, span_lint_hir_and_then},
-    eq_expr_value,
-    higher::If,
-    is_diag_trait_item, is_trait_method, meets_msrv, msrvs, path_res, path_to_local_id, peel_blocks,
-    peel_blocks_with_stmt,
-    sugg::Sugg,
-    ty::implements_trait,
-    visitors::is_const_evaluatable,
-    MaybePath,
-};
-use rustc_errors::Applicability;
-
 declare_clippy_lint! {
     /// ### What it does
     /// Identifies good opportunities for a clamp function from std or core, and suggests using it.
 impl_lint_pass!(ManualClamp => [MANUAL_CLAMP]);
 
 pub struct ManualClamp {
-    msrv: Option<RustcVersion>,
+    msrv: Msrv,
 }
 
 impl ManualClamp {
-    pub fn new(msrv: Option<RustcVersion>) -> Self {
+    pub fn new(msrv: Msrv) -> Self {
         Self { msrv }
     }
 }
@@ -114,7 +111,7 @@ struct InputMinMax<'tcx> {
 
 impl<'tcx> LateLintPass<'tcx> for ManualClamp {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
-        if !meets_msrv(self.msrv, msrvs::CLAMP) {
+        if !self.msrv.meets(msrvs::CLAMP) {
             return;
         }
         if !expr.span.from_expansion() {
@@ -130,7 +127,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
     }
 
     fn check_block(&mut self, cx: &LateContext<'tcx>, block: &'tcx Block<'tcx>) {
-        if !meets_msrv(self.msrv, msrvs::CLAMP) {
+        if !self.msrv.meets(msrvs::CLAMP) {
             return;
         }
         for suggestion in is_two_if_pattern(cx, block) {
index bb8c142f8e4680e3b1ccea794cedc942f903d5e3..5ab049d8d133fd34629227da15fbfef84c255915 100644 (file)
@@ -1,15 +1,12 @@
+use clippy_utils::msrvs::{self, Msrv};
+use clippy_utils::{diagnostics::span_lint_and_sugg, in_constant, macros::root_macro_call, source::snippet};
 use rustc_ast::LitKind::{Byte, Char};
 use rustc_errors::Applicability;
 use rustc_hir::{Expr, ExprKind, PatKind, RangeEnd};
 use rustc_lint::{LateContext, LateLintPass};
-use rustc_semver::RustcVersion;
 use rustc_session::{declare_tool_lint, impl_lint_pass};
 use rustc_span::{def_id::DefId, sym};
 
-use clippy_utils::{
-    diagnostics::span_lint_and_sugg, in_constant, macros::root_macro_call, meets_msrv, msrvs, source::snippet,
-};
-
 declare_clippy_lint! {
     /// ### What it does
     /// Suggests to use dedicated built-in methods,
 impl_lint_pass!(ManualIsAsciiCheck => [MANUAL_IS_ASCII_CHECK]);
 
 pub struct ManualIsAsciiCheck {
-    msrv: Option<RustcVersion>,
+    msrv: Msrv,
 }
 
 impl ManualIsAsciiCheck {
     #[must_use]
-    pub fn new(msrv: Option<RustcVersion>) -> Self {
+    pub fn new(msrv: Msrv) -> Self {
         Self { msrv }
     }
 }
@@ -70,11 +67,11 @@ enum CharRange {
 
 impl<'tcx> LateLintPass<'tcx> for ManualIsAsciiCheck {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
-        if !meets_msrv(self.msrv, msrvs::IS_ASCII_DIGIT) {
+        if !self.msrv.meets(msrvs::IS_ASCII_DIGIT) {
             return;
         }
 
-        if in_constant(cx, expr.hir_id) && !meets_msrv(self.msrv, msrvs::IS_ASCII_DIGIT_CONST) {
+        if in_constant(cx, expr.hir_id) && !self.msrv.meets(msrvs::IS_ASCII_DIGIT_CONST) {
             return;
         }
 
index 1846596fa4c8e259ab6f0ffb580807a47de5381b..874d36ca9f4e378704019c8ae971c046c68d898c 100644 (file)
@@ -1,16 +1,16 @@
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::higher::IfLetOrMatch;
-use clippy_utils::source::snippet_opt;
+use clippy_utils::msrvs::{self, Msrv};
+use clippy_utils::peel_blocks;
+use clippy_utils::source::snippet_with_context;
 use clippy_utils::ty::is_type_diagnostic_item;
 use clippy_utils::visitors::{for_each_expr, Descend};
-use clippy_utils::{meets_msrv, msrvs, peel_blocks};
 use if_chain::if_chain;
 use rustc_data_structures::fx::FxHashSet;
 use rustc_errors::Applicability;
 use rustc_hir::{Expr, ExprKind, MatchSource, Pat, PatKind, QPath, Stmt, StmtKind};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
 use rustc_middle::lint::in_external_macro;
-use rustc_semver::RustcVersion;
 use rustc_session::{declare_tool_lint, impl_lint_pass};
 use rustc_span::symbol::sym;
 use rustc_span::Span;
 }
 
 pub struct ManualLetElse {
-    msrv: Option<RustcVersion>,
+    msrv: Msrv,
     matches_behaviour: MatchLintBehaviour,
 }
 
 impl ManualLetElse {
     #[must_use]
-    pub fn new(msrv: Option<RustcVersion>, matches_behaviour: MatchLintBehaviour) -> Self {
+    pub fn new(msrv: Msrv, matches_behaviour: MatchLintBehaviour) -> Self {
         Self {
             msrv,
             matches_behaviour,
@@ -69,7 +69,7 @@ pub fn new(msrv: Option<RustcVersion>, matches_behaviour: MatchLintBehaviour) ->
 impl<'tcx> LateLintPass<'tcx> for ManualLetElse {
     fn check_stmt(&mut self, cx: &LateContext<'_>, stmt: &'tcx Stmt<'tcx>) {
         let if_let_or_match = if_chain! {
-            if meets_msrv(self.msrv, msrvs::LET_ELSE);
+            if self.msrv.meets(msrvs::LET_ELSE);
             if !in_external_macro(cx.sess(), stmt.span);
             if let StmtKind::Local(local) = stmt.kind;
             if let Some(init) = local.init;
@@ -141,20 +141,18 @@ fn emit_manual_let_else(cx: &LateContext<'_>, span: Span, expr: &Expr<'_>, pat:
             // * unused binding collision detection with existing ones
             // * putting patterns with at the top level | inside ()
             // for this to be machine applicable.
-            let app = Applicability::HasPlaceholders;
+            let mut app = Applicability::HasPlaceholders;
+            let (sn_pat, _) = snippet_with_context(cx, pat.span, span.ctxt(), "", &mut app);
+            let (sn_expr, _) = snippet_with_context(cx, expr.span, span.ctxt(), "", &mut app);
+            let (sn_else, _) = snippet_with_context(cx, else_body.span, span.ctxt(), "", &mut app);
 
-            if let Some(sn_pat) = snippet_opt(cx, pat.span) &&
-                let Some(sn_expr) = snippet_opt(cx, expr.span) &&
-                let Some(sn_else) = snippet_opt(cx, else_body.span)
-            {
-                let else_bl = if matches!(else_body.kind, ExprKind::Block(..)) {
-                    sn_else
-                } else {
-                    format!("{{ {sn_else} }}")
-                };
-                let sugg = format!("let {sn_pat} = {sn_expr} else {else_bl};");
-                diag.span_suggestion(span, "consider writing", sugg, app);
-            }
+            let else_bl = if matches!(else_body.kind, ExprKind::Block(..)) {
+                sn_else.into_owned()
+            } else {
+                format!("{{ {sn_else} }}")
+            };
+            let sugg = format!("let {sn_pat} = {sn_expr} else {else_bl};");
+            diag.span_suggestion(span, "consider writing", sugg, app);
         },
     );
 }
index 4877cee0cc1ea8ea8bc3b575cb38272e84a94b17..bca193be9e711a520e3e4774c0c55a6af72559b8 100644 (file)
@@ -1,6 +1,7 @@
 use clippy_utils::diagnostics::{span_lint_and_then, span_lint_hir_and_then};
+use clippy_utils::is_doc_hidden;
+use clippy_utils::msrvs::{self, Msrv};
 use clippy_utils::source::snippet_opt;
-use clippy_utils::{is_doc_hidden, meets_msrv, msrvs};
 use rustc_ast::ast::{self, VisibilityKind};
 use rustc_data_structures::fx::FxHashSet;
 use rustc_errors::Applicability;
@@ -8,7 +9,6 @@
 use rustc_hir::{self as hir, Expr, ExprKind, QPath};
 use rustc_lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext};
 use rustc_middle::ty::DefIdTree;
-use rustc_semver::RustcVersion;
 use rustc_session::{declare_tool_lint, impl_lint_pass};
 use rustc_span::def_id::{DefId, LocalDefId};
 use rustc_span::{sym, Span};
 
 #[expect(clippy::module_name_repetitions)]
 pub struct ManualNonExhaustiveStruct {
-    msrv: Option<RustcVersion>,
+    msrv: Msrv,
 }
 
 impl ManualNonExhaustiveStruct {
     #[must_use]
-    pub fn new(msrv: Option<RustcVersion>) -> Self {
+    pub fn new(msrv: Msrv) -> Self {
         Self { msrv }
     }
 }
@@ -77,14 +77,14 @@ pub fn new(msrv: Option<RustcVersion>) -> Self {
 
 #[expect(clippy::module_name_repetitions)]
 pub struct ManualNonExhaustiveEnum {
-    msrv: Option<RustcVersion>,
+    msrv: Msrv,
     constructed_enum_variants: FxHashSet<(DefId, DefId)>,
     potential_enums: Vec<(LocalDefId, LocalDefId, Span, Span)>,
 }
 
 impl ManualNonExhaustiveEnum {
     #[must_use]
-    pub fn new(msrv: Option<RustcVersion>) -> Self {
+    pub fn new(msrv: Msrv) -> Self {
         Self {
             msrv,
             constructed_enum_variants: FxHashSet::default(),
@@ -97,7 +97,7 @@ pub fn new(msrv: Option<RustcVersion>) -> Self {
 
 impl EarlyLintPass for ManualNonExhaustiveStruct {
     fn check_item(&mut self, cx: &EarlyContext<'_>, item: &ast::Item) {
-        if !meets_msrv(self.msrv, msrvs::NON_EXHAUSTIVE) {
+        if !self.msrv.meets(msrvs::NON_EXHAUSTIVE) {
             return;
         }
 
@@ -149,7 +149,7 @@ fn check_item(&mut self, cx: &EarlyContext<'_>, item: &ast::Item) {
 
 impl<'tcx> LateLintPass<'tcx> for ManualNonExhaustiveEnum {
     fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) {
-        if !meets_msrv(self.msrv, msrvs::NON_EXHAUSTIVE) {
+        if !self.msrv.meets(msrvs::NON_EXHAUSTIVE) {
             return;
         }
 
index 6f25a2ed8e434f60b11025d4943f6127a9848f1c..8d447c37150b8d2a01f095755e878dbf13740b08 100644 (file)
@@ -1,12 +1,12 @@
 use clippy_utils::consts::{constant_full_int, FullInt};
 use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::msrvs::{self, Msrv};
 use clippy_utils::source::snippet_with_applicability;
-use clippy_utils::{in_constant, meets_msrv, msrvs, path_to_local};
+use clippy_utils::{in_constant, path_to_local};
 use rustc_errors::Applicability;
 use rustc_hir::{BinOpKind, Expr, ExprKind, Node, TyKind};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
 use rustc_middle::lint::in_external_macro;
-use rustc_semver::RustcVersion;
 use rustc_session::{declare_tool_lint, impl_lint_pass};
 
 declare_clippy_lint! {
 }
 
 pub struct ManualRemEuclid {
-    msrv: Option<RustcVersion>,
+    msrv: Msrv,
 }
 
 impl ManualRemEuclid {
     #[must_use]
-    pub fn new(msrv: Option<RustcVersion>) -> Self {
+    pub fn new(msrv: Msrv) -> Self {
         Self { msrv }
     }
 }
@@ -48,11 +48,11 @@ pub fn new(msrv: Option<RustcVersion>) -> Self {
 
 impl<'tcx> LateLintPass<'tcx> for ManualRemEuclid {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
-        if !meets_msrv(self.msrv, msrvs::REM_EUCLID) {
+        if !self.msrv.meets(msrvs::REM_EUCLID) {
             return;
         }
 
-        if in_constant(cx, expr.hir_id) && !meets_msrv(self.msrv, msrvs::REM_EUCLID_CONST) {
+        if in_constant(cx, expr.hir_id) && !self.msrv.meets(msrvs::REM_EUCLID_CONST) {
             return;
         }
 
index d6438ca7fec2aca306b8be7c776eef7fef382b33..c1e6c82487dc54d79b5e86185541108c149af35e 100644 (file)
@@ -1,8 +1,8 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::msrvs::{self, Msrv};
 use clippy_utils::source::snippet;
 use clippy_utils::ty::{is_type_diagnostic_item, is_type_lang_item};
 use clippy_utils::{get_parent_expr, match_def_path, paths, SpanlessEq};
-use clippy_utils::{meets_msrv, msrvs};
 use rustc_errors::Applicability;
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
 }
 
 pub struct ManualRetain {
-    msrv: Option<RustcVersion>,
+    msrv: Msrv,
 }
 
 impl ManualRetain {
     #[must_use]
-    pub fn new(msrv: Option<RustcVersion>) -> Self {
+    pub fn new(msrv: Msrv) -> Self {
         Self { msrv }
     }
 }
@@ -71,9 +71,9 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
             && let hir::ExprKind::MethodCall(_, target_expr, [], _) = &collect_expr.kind
             && let Some(collect_def_id) = cx.typeck_results().type_dependent_def_id(collect_expr.hir_id)
             && match_def_path(cx, collect_def_id, &paths::CORE_ITER_COLLECT) {
-            check_into_iter(cx, parent_expr, left_expr, target_expr, self.msrv);
-            check_iter(cx, parent_expr, left_expr, target_expr, self.msrv);
-            check_to_owned(cx, parent_expr, left_expr, target_expr, self.msrv);
+            check_into_iter(cx, parent_expr, left_expr, target_expr, &self.msrv);
+            check_iter(cx, parent_expr, left_expr, target_expr, &self.msrv);
+            check_to_owned(cx, parent_expr, left_expr, target_expr, &self.msrv);
         }
     }
 
@@ -85,7 +85,7 @@ fn check_into_iter(
     parent_expr: &hir::Expr<'_>,
     left_expr: &hir::Expr<'_>,
     target_expr: &hir::Expr<'_>,
-    msrv: Option<RustcVersion>,
+    msrv: &Msrv,
 ) {
     if let hir::ExprKind::MethodCall(_, into_iter_expr, [_], _) = &target_expr.kind
         && let Some(filter_def_id) = cx.typeck_results().type_dependent_def_id(target_expr.hir_id)
@@ -104,7 +104,7 @@ fn check_iter(
     parent_expr: &hir::Expr<'_>,
     left_expr: &hir::Expr<'_>,
     target_expr: &hir::Expr<'_>,
-    msrv: Option<RustcVersion>,
+    msrv: &Msrv,
 ) {
     if let hir::ExprKind::MethodCall(_, filter_expr, [], _) = &target_expr.kind
         && let Some(copied_def_id) = cx.typeck_results().type_dependent_def_id(target_expr.hir_id)
@@ -127,9 +127,9 @@ fn check_to_owned(
     parent_expr: &hir::Expr<'_>,
     left_expr: &hir::Expr<'_>,
     target_expr: &hir::Expr<'_>,
-    msrv: Option<RustcVersion>,
+    msrv: &Msrv,
 ) {
-    if meets_msrv(msrv,  msrvs::STRING_RETAIN)
+    if msrv.meets(msrvs::STRING_RETAIN)
         && let hir::ExprKind::MethodCall(_, filter_expr, [], _) = &target_expr.kind
         && let Some(to_owned_def_id) = cx.typeck_results().type_dependent_def_id(target_expr.hir_id)
         && match_def_path(cx, to_owned_def_id, &paths::TO_OWNED_METHOD)
@@ -215,10 +215,10 @@ fn match_acceptable_def_path(cx: &LateContext<'_>, collect_def_id: DefId) -> boo
         .any(|&method| match_def_path(cx, collect_def_id, method))
 }
 
-fn match_acceptable_type(cx: &LateContext<'_>, expr: &hir::Expr<'_>, msrv: Option<RustcVersion>) -> bool {
+fn match_acceptable_type(cx: &LateContext<'_>, expr: &hir::Expr<'_>, msrv: &Msrv) -> bool {
     let expr_ty = cx.typeck_results().expr_ty(expr).peel_refs();
     ACCEPTABLE_TYPES.iter().any(|(ty, acceptable_msrv)| {
         is_type_diagnostic_item(cx, expr_ty, *ty)
-            && acceptable_msrv.map_or(true, |acceptable_msrv| meets_msrv(msrv, acceptable_msrv))
+            && acceptable_msrv.map_or(true, |acceptable_msrv| msrv.meets(acceptable_msrv))
     })
 }
index 0976940afac355fcc9f9b02f9796cf4262023018..de166b9765f4194b6ff22e909c8a370c3200146d 100644 (file)
@@ -1,8 +1,9 @@
 use clippy_utils::consts::{constant, Constant};
 use clippy_utils::diagnostics::{multispan_sugg, span_lint_and_then};
+use clippy_utils::msrvs::{self, Msrv};
 use clippy_utils::source::snippet;
 use clippy_utils::usage::mutated_variables;
-use clippy_utils::{eq_expr_value, higher, match_def_path, meets_msrv, msrvs, paths};
+use clippy_utils::{eq_expr_value, higher, match_def_path, paths};
 use if_chain::if_chain;
 use rustc_ast::ast::LitKind;
 use rustc_hir::def::Res;
@@ -11,7 +12,6 @@
 use rustc_hir::{BorrowKind, Expr, ExprKind};
 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::Spanned;
 use rustc_span::Span;
 }
 
 pub struct ManualStrip {
-    msrv: Option<RustcVersion>,
+    msrv: Msrv,
 }
 
 impl ManualStrip {
     #[must_use]
-    pub fn new(msrv: Option<RustcVersion>) -> Self {
+    pub fn new(msrv: Msrv) -> Self {
         Self { msrv }
     }
 }
@@ -68,7 +68,7 @@ enum StripKind {
 
 impl<'tcx> LateLintPass<'tcx> for ManualStrip {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
-        if !meets_msrv(self.msrv, msrvs::STR_STRIP_PREFIX) {
+        if !self.msrv.meets(msrvs::STR_STRIP_PREFIX) {
             return;
         }
 
index 7d8171ead89e10787dee90e48d11a7e33b527a6a..7b15a307fecf47d66a50a013117e83eabd28602c 100644 (file)
 mod try_err;
 mod wild_in_or_pats;
 
+use clippy_utils::msrvs::{self, Msrv};
 use clippy_utils::source::{snippet_opt, walk_span_to_context};
-use clippy_utils::{higher, in_constant, is_span_match, meets_msrv, msrvs};
+use clippy_utils::{higher, in_constant, is_span_match};
 use rustc_hir::{Arm, Expr, ExprKind, Local, MatchSource, Pat};
 use rustc_lexer::{tokenize, TokenKind};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
 use rustc_middle::lint::in_external_macro;
-use rustc_semver::RustcVersion;
 use rustc_session::{declare_tool_lint, impl_lint_pass};
 use rustc_span::{Span, SpanData, SyntaxContext};
 
 
 #[derive(Default)]
 pub struct Matches {
-    msrv: Option<RustcVersion>,
+    msrv: Msrv,
     infallible_destructuring_match_linted: bool,
 }
 
 impl Matches {
     #[must_use]
-    pub fn new(msrv: Option<RustcVersion>) -> Self {
+    pub fn new(msrv: Msrv) -> Self {
         Self {
             msrv,
             ..Matches::default()
@@ -1000,9 +1000,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
 
             if !from_expansion && !contains_cfg_arm(cx, expr, ex, arms) {
                 if source == MatchSource::Normal {
-                    if !(meets_msrv(self.msrv, msrvs::MATCHES_MACRO)
-                        && match_like_matches::check_match(cx, expr, ex, arms))
-                    {
+                    if !(self.msrv.meets(msrvs::MATCHES_MACRO) && match_like_matches::check_match(cx, expr, ex, arms)) {
                         match_same_arms::check(cx, arms);
                     }
 
@@ -1034,7 +1032,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
             collapsible_match::check_if_let(cx, if_let.let_pat, if_let.if_then, if_let.if_else);
             if !from_expansion {
                 if let Some(else_expr) = if_let.if_else {
-                    if meets_msrv(self.msrv, msrvs::MATCHES_MACRO) {
+                    if self.msrv.meets(msrvs::MATCHES_MACRO) {
                         match_like_matches::check_if_let(
                             cx,
                             expr,
index c6cba81d8718972e89d436f83a3b4ef2facd37e2..704c34c32bf743b39842571202e1114e5b28a750 100644 (file)
@@ -1,7 +1,7 @@
 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::{get_parent_expr, is_res_lang_ctor, match_def_path, path_res, paths};
+use clippy_utils::{get_parent_expr, is_res_lang_ctor, path_res};
 use if_chain::if_chain;
 use rustc_errors::Applicability;
 use rustc_hir::LangItem::ResultErr;
@@ -107,7 +107,7 @@ fn result_error_type<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<Ty<'t
 fn poll_result_error_type<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<Ty<'tcx>> {
     if_chain! {
         if let ty::Adt(def, subst) = ty.kind();
-        if match_def_path(cx, def.did(), &paths::POLL);
+        if cx.tcx.lang_items().get(LangItem::Poll) == Some(def.did());
         let ready_ty = subst.type_at(0);
 
         if let ty::Adt(ready_def, ready_subst) = ready_ty.kind();
@@ -124,7 +124,7 @@ fn poll_result_error_type<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<
 fn poll_option_result_error_type<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<Ty<'tcx>> {
     if_chain! {
         if let ty::Adt(def, subst) = ty.kind();
-        if match_def_path(cx, def.did(), &paths::POLL);
+        if cx.tcx.lang_items().get(LangItem::Poll) == Some(def.did());
         let ready_ty = subst.type_at(0);
 
         if let ty::Adt(ready_def, ready_subst) = ready_ty.kind();
index 0c4d9f100f7a966f7c3bade76f7e3843b3518f70..35024ec1224f04053e5d6ac01c71c2c20b8c5a00 100644 (file)
@@ -1,14 +1,14 @@
 use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_sugg, span_lint_and_then};
+use clippy_utils::msrvs::{self, Msrv};
 use clippy_utils::source::{snippet, snippet_with_applicability};
 use clippy_utils::ty::is_non_aggregate_primitive_type;
-use clippy_utils::{is_default_equivalent, is_res_lang_ctor, meets_msrv, msrvs, path_res};
+use clippy_utils::{is_default_equivalent, is_res_lang_ctor, path_res};
 use if_chain::if_chain;
 use rustc_errors::Applicability;
 use rustc_hir::LangItem::OptionNone;
 use rustc_hir::{BorrowKind, Expr, ExprKind, Mutability, QPath};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::lint::in_external_macro;
-use rustc_semver::RustcVersion;
 use rustc_session::{declare_tool_lint, impl_lint_pass};
 use rustc_span::source_map::Span;
 use rustc_span::symbol::sym;
@@ -227,12 +227,12 @@ fn check_replace_with_default(cx: &LateContext<'_>, src: &Expr<'_>, dest: &Expr<
 }
 
 pub struct MemReplace {
-    msrv: Option<RustcVersion>,
+    msrv: Msrv,
 }
 
 impl MemReplace {
     #[must_use]
-    pub fn new(msrv: Option<RustcVersion>) -> Self {
+    pub fn new(msrv: Msrv) -> Self {
         Self { msrv }
     }
 }
@@ -248,7 +248,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
             then {
                 check_replace_option_with_none(cx, src, dest, expr.span);
                 check_replace_with_uninit(cx, src, dest, expr.span);
-                if meets_msrv(self.msrv, msrvs::MEM_TAKE) {
+                if self.msrv.meets(msrvs::MEM_TAKE) {
                     check_replace_with_default(cx, src, dest, expr.span);
                 }
             }
index e9aeab2d5b62e37180d67dc5bc64b75b12fa8666..4e6ec61f6a83dab5b14f96a8c8920001a071e822 100644 (file)
@@ -1,25 +1,25 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::is_trait_method;
+use clippy_utils::msrvs::{self, Msrv};
 use clippy_utils::ty::{get_iterator_item_ty, is_copy};
-use clippy_utils::{is_trait_method, meets_msrv, msrvs};
 use rustc_errors::Applicability;
 use rustc_hir::Expr;
 use rustc_lint::LateContext;
 use rustc_middle::ty;
-use rustc_semver::RustcVersion;
 use rustc_span::{sym, Span};
 
 use super::CLONED_INSTEAD_OF_COPIED;
 
-pub fn check(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, span: Span, msrv: Option<RustcVersion>) {
+pub fn check(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, span: Span, msrv: &Msrv) {
     let recv_ty = cx.typeck_results().expr_ty_adjusted(recv);
     let inner_ty = match recv_ty.kind() {
         // `Option<T>` -> `T`
         ty::Adt(adt, subst)
-            if cx.tcx.is_diagnostic_item(sym::Option, adt.did()) && meets_msrv(msrv, msrvs::OPTION_COPIED) =>
+            if cx.tcx.is_diagnostic_item(sym::Option, adt.did()) && msrv.meets(msrvs::OPTION_COPIED) =>
         {
             subst.type_at(0)
         },
-        _ if is_trait_method(cx, expr, sym::Iterator) && meets_msrv(msrv, msrvs::ITERATOR_COPIED) => {
+        _ if is_trait_method(cx, expr, sym::Iterator) && msrv.meets(msrvs::ITERATOR_COPIED) => {
             match get_iterator_item_ty(cx, recv_ty) {
                 // <T as Iterator>::Item
                 Some(ty) => ty,
index 720d9a68c85ee81bf43e2f34ed7fe7042415110b..ae03da0d3f9ce3296a8ee70f8712b5ffc8587e44 100644 (file)
@@ -1,27 +1,27 @@
 use super::ERR_EXPECT;
 use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::msrvs::{self, Msrv};
 use clippy_utils::ty::has_debug_impl;
-use clippy_utils::{meets_msrv, msrvs, ty::is_type_diagnostic_item};
+use clippy_utils::ty::is_type_diagnostic_item;
 use rustc_errors::Applicability;
 use rustc_lint::LateContext;
 use rustc_middle::ty;
 use rustc_middle::ty::Ty;
-use rustc_semver::RustcVersion;
 use rustc_span::{sym, Span};
 
 pub(super) fn check(
     cx: &LateContext<'_>,
     _expr: &rustc_hir::Expr<'_>,
     recv: &rustc_hir::Expr<'_>,
-    msrv: Option<RustcVersion>,
     expect_span: Span,
     err_span: Span,
+    msrv: &Msrv,
 ) {
     if_chain! {
         if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv), sym::Result);
         // Test the version to make sure the lint can be showed (expect_err has been
         // introduced in rust 1.17.0 : https://github.com/rust-lang/rust/pull/38982)
-        if meets_msrv(msrv, msrvs::EXPECT_ERR);
+        if msrv.meets(msrvs::EXPECT_ERR);
 
         // Grabs the `Result<T, E>` type
         let result_type = cx.typeck_results().expr_ty(recv);
index ddf8a1f09b87d4b21b21704bc4bd1209a10600ad..175e04f8ac061bd4d5d0305afa3c04bf01d24d44 100644 (file)
@@ -1,10 +1,10 @@
 use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg};
+use clippy_utils::is_trait_method;
+use clippy_utils::msrvs::{self, Msrv};
 use clippy_utils::source::snippet;
-use clippy_utils::{is_trait_method, meets_msrv, msrvs};
 use rustc_errors::Applicability;
 use rustc_hir as hir;
 use rustc_lint::LateContext;
-use rustc_semver::RustcVersion;
 use rustc_span::sym;
 
 use super::FILTER_MAP_NEXT;
@@ -14,10 +14,10 @@ pub(super) fn check<'tcx>(
     expr: &'tcx hir::Expr<'_>,
     recv: &'tcx hir::Expr<'_>,
     arg: &'tcx hir::Expr<'_>,
-    msrv: Option<RustcVersion>,
+    msrv: &Msrv,
 ) {
     if is_trait_method(cx, expr, sym::Iterator) {
-        if !meets_msrv(msrv, msrvs::ITERATOR_FIND_MAP) {
+        if !msrv.meets(msrvs::ITERATOR_FIND_MAP) {
             return;
         }
 
index 304024e80666f882e7eaff6bce448c734e1d3348..301aff5ae6ac0ba21ebba1dbc8ee98d6af2d465f 100644 (file)
@@ -1,23 +1,22 @@
 //! Lint for `c.is_digit(10)`
 
 use super::IS_DIGIT_ASCII_RADIX;
+use clippy_utils::msrvs::{self, Msrv};
 use clippy_utils::{
-    consts::constant_full_int, consts::FullInt, diagnostics::span_lint_and_sugg, meets_msrv, msrvs,
-    source::snippet_with_applicability,
+    consts::constant_full_int, consts::FullInt, diagnostics::span_lint_and_sugg, source::snippet_with_applicability,
 };
 use rustc_errors::Applicability;
 use rustc_hir::Expr;
 use rustc_lint::LateContext;
-use rustc_semver::RustcVersion;
 
 pub(super) fn check<'tcx>(
     cx: &LateContext<'tcx>,
     expr: &'tcx Expr<'_>,
     self_arg: &'tcx Expr<'_>,
     radix: &'tcx Expr<'_>,
-    msrv: Option<RustcVersion>,
+    msrv: &Msrv,
 ) {
-    if !meets_msrv(msrv, msrvs::IS_ASCII_DIGIT) {
+    if !msrv.meets(msrvs::IS_ASCII_DIGIT) {
         return;
     }
 
index 6bc783c6d505af108a508067f772a9fefcda5103..52cc1e0464bf331cd3f624cfff75d725e5af9773 100644 (file)
@@ -1,7 +1,8 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::msrvs::{self, Msrv};
 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 clippy_utils::{is_diag_trait_item, peel_blocks};
 use if_chain::if_chain;
 use rustc_errors::Applicability;
 use rustc_hir as hir;
 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(
-    cx: &LateContext<'_>,
-    e: &hir::Expr<'_>,
-    recv: &hir::Expr<'_>,
-    arg: &hir::Expr<'_>,
-    msrv: Option<RustcVersion>,
-) {
+pub(super) fn check(cx: &LateContext<'_>, e: &hir::Expr<'_>, recv: &hir::Expr<'_>, arg: &hir::Expr<'_>, msrv: &Msrv) {
     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)
@@ -97,10 +91,10 @@ fn lint_needless_cloning(cx: &LateContext<'_>, root: Span, receiver: Span) {
     );
 }
 
-fn lint_explicit_closure(cx: &LateContext<'_>, replace: Span, root: Span, is_copy: bool, msrv: Option<RustcVersion>) {
+fn lint_explicit_closure(cx: &LateContext<'_>, replace: Span, root: Span, is_copy: bool, msrv: &Msrv) {
     let mut applicability = Applicability::MachineApplicable;
 
-    let (message, sugg_method) = if is_copy && meets_msrv(msrv, msrvs::ITERATOR_COPIED) {
+    let (message, sugg_method) = if is_copy && msrv.meets(msrvs::ITERATOR_COPIED) {
         ("you are using an explicit closure for copying elements", "copied")
     } else {
         ("you are using an explicit closure for cloning elements", "cloned")
index 74fdead216b0a5f7c3df156b51c21cf83a1a59ac..3122f72ee9155ad932c50eb9e721663a0d74d1b3 100644 (file)
@@ -1,12 +1,11 @@
 use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg};
+use clippy_utils::msrvs::{self, Msrv};
 use clippy_utils::source::snippet;
 use clippy_utils::ty::is_type_diagnostic_item;
 use clippy_utils::usage::mutated_variables;
-use clippy_utils::{meets_msrv, msrvs};
 use rustc_errors::Applicability;
 use rustc_hir as hir;
 use rustc_lint::LateContext;
-use rustc_semver::RustcVersion;
 use rustc_span::symbol::sym;
 
 use super::MAP_UNWRAP_OR;
@@ -19,13 +18,13 @@ pub(super) fn check<'tcx>(
     recv: &'tcx hir::Expr<'_>,
     map_arg: &'tcx hir::Expr<'_>,
     unwrap_arg: &'tcx hir::Expr<'_>,
-    msrv: Option<RustcVersion>,
+    msrv: &Msrv,
 ) -> bool {
     // lint if the caller of `map()` is an `Option`
     let is_option = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv), sym::Option);
     let is_result = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv), sym::Result);
 
-    if is_result && !meets_msrv(msrv, msrvs::RESULT_MAP_OR_ELSE) {
+    if is_result && !msrv.meets(msrvs::RESULT_MAP_OR_ELSE) {
         return false;
     }
 
index 38165ab4fb26f4053a256c012a933307538b8452..d2913680cbb742a11db2439aa668aff4d0a979c0 100644 (file)
 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::msrvs::{self, Msrv};
 use clippy_utils::ty::{contains_ty_adt_constructor_opaque, implements_trait, is_copy, is_type_diagnostic_item};
-use clippy_utils::{contains_return, is_bool, is_trait_method, iter_input_pats, meets_msrv, msrvs, return_ty};
+use clippy_utils::{contains_return, is_bool, is_trait_method, iter_input_pats, return_ty};
 use if_chain::if_chain;
 use rustc_hir as hir;
 use rustc_hir::{Expr, ExprKind, TraitItem, TraitItemKind};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
 use rustc_middle::lint::in_external_macro;
 use rustc_middle::ty::{self, TraitRef, Ty};
-use rustc_semver::RustcVersion;
 use rustc_session::{declare_tool_lint, impl_lint_pass};
 use rustc_span::{sym, Span};
 
 
 pub struct Methods {
     avoid_breaking_exported_api: bool,
-    msrv: Option<RustcVersion>,
+    msrv: Msrv,
     allow_expect_in_tests: bool,
     allow_unwrap_in_tests: bool,
 }
@@ -3172,7 +3172,7 @@ impl Methods {
     #[must_use]
     pub fn new(
         avoid_breaking_exported_api: bool,
-        msrv: Option<RustcVersion>,
+        msrv: Msrv,
         allow_expect_in_tests: bool,
         allow_unwrap_in_tests: bool,
     ) -> Self {
@@ -3325,7 +3325,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
                 single_char_add_str::check(cx, expr, receiver, args);
                 into_iter_on_ref::check(cx, expr, method_span, method_call.ident.name, receiver);
                 single_char_pattern::check(cx, expr, method_call.ident.name, receiver, args);
-                unnecessary_to_owned::check(cx, expr, method_call.ident.name, receiver, args, self.msrv);
+                unnecessary_to_owned::check(cx, expr, method_call.ident.name, receiver, args, &self.msrv);
             },
             hir::ExprKind::Binary(op, lhs, rhs) if op.node == hir::BinOpKind::Eq || op.node == hir::BinOpKind::Ne => {
                 let mut info = BinaryExprInfo {
@@ -3501,7 +3501,7 @@ fn check_methods<'tcx>(&self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
                 ("as_mut", []) => useless_asref::check(cx, expr, "as_mut", recv),
                 ("as_ref", []) => useless_asref::check(cx, expr, "as_ref", recv),
                 ("assume_init", []) => uninit_assumed_init::check(cx, expr, recv),
-                ("cloned", []) => cloned_instead_of_copied::check(cx, expr, recv, span, self.msrv),
+                ("cloned", []) => cloned_instead_of_copied::check(cx, expr, recv, span, &self.msrv),
                 ("collect", []) if is_trait_method(cx, expr, sym::Iterator) => {
                     needless_collect::check(cx, span, expr, recv, call_span);
                     match method_call(recv) {
@@ -3512,7 +3512,7 @@ fn check_methods<'tcx>(&self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
                             map_collect_result_unit::check(cx, expr, m_recv, m_arg);
                         },
                         Some(("take", take_self_arg, [take_arg], _, _)) => {
-                            if meets_msrv(self.msrv, msrvs::STR_REPEAT) {
+                            if self.msrv.meets(msrvs::STR_REPEAT) {
                                 manual_str_repeat::check(cx, expr, recv, take_self_arg, take_arg);
                             }
                         },
@@ -3539,7 +3539,7 @@ fn check_methods<'tcx>(&self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
                 },
                 ("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),
+                    Some(("err", recv, [], err_span, _)) => err_expect::check(cx, expr, recv, span, err_span, &self.msrv),
                     _ => 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),
@@ -3578,7 +3578,7 @@ fn check_methods<'tcx>(&self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
                     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_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", []) => {
@@ -3601,7 +3601,7 @@ fn check_methods<'tcx>(&self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
                 },
                 (name @ ("map" | "map_err"), [m_arg]) => {
                     if name == "map" {
-                        map_clone::check(cx, expr, recv, m_arg, self.msrv);
+                        map_clone::check(cx, expr, recv, m_arg, &self.msrv);
                         if let Some((map_name @ ("iter" | "into_iter"), recv2, _, _, _)) = method_call(recv) {
                             iter_kv_map::check(cx, map_name, expr, recv2, m_arg);
                         }
@@ -3610,8 +3610,8 @@ fn check_methods<'tcx>(&self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
                     }
                     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),
-                            ("as_ref", []) => option_as_ref_deref::check(cx, expr, recv2, m_arg, false, self.msrv),
+                            ("as_mut", []) => option_as_ref_deref::check(cx, expr, recv2, m_arg, true, &self.msrv),
+                            ("as_ref", []) => option_as_ref_deref::check(cx, expr, recv2, m_arg, false, &self.msrv),
                             ("filter", [f_arg]) => {
                                 filter_map::check(cx, expr, recv2, f_arg, span2, recv, m_arg, span, false);
                             },
@@ -3632,7 +3632,7 @@ fn check_methods<'tcx>(&self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
                         match (name2, args2) {
                             ("cloned", []) => iter_overeager_cloned::check(cx, expr, recv, recv2, false, false),
                             ("filter", [arg]) => filter_next::check(cx, expr, recv2, arg),
-                            ("filter_map", [arg]) => filter_map_next::check(cx, expr, recv2, arg, self.msrv),
+                            ("filter_map", [arg]) => filter_map_next::check(cx, expr, recv2, arg, &self.msrv),
                             ("iter", []) => iter_next_slice::check(cx, expr, recv2),
                             ("skip", [arg]) => iter_skip_next::check(cx, expr, recv2, arg),
                             ("skip_while", [_]) => skip_while_next::check(cx, expr),
@@ -3680,10 +3680,10 @@ fn check_methods<'tcx>(&self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
                     vec_resize_to_zero::check(cx, expr, count_arg, default_arg, span);
                 },
                 ("seek", [arg]) => {
-                    if meets_msrv(self.msrv, msrvs::SEEK_FROM_CURRENT) {
+                    if self.msrv.meets(msrvs::SEEK_FROM_CURRENT) {
                         seek_from_current::check(cx, expr, recv, arg);
                     }
-                    if meets_msrv(self.msrv, msrvs::SEEK_REWIND) {
+                    if self.msrv.meets(msrvs::SEEK_REWIND) {
                         seek_to_start_instead_of_rewind::check(cx, expr, recv, arg, span);
                     }
                 },
@@ -3699,7 +3699,7 @@ fn check_methods<'tcx>(&self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
                 ("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);
-                        str_splitn::check(cx, name, expr, recv, pat_arg, count, self.msrv);
+                        str_splitn::check(cx, name, expr, recv, pat_arg, count, &self.msrv);
                     }
                 },
                 ("splitn_mut" | "rsplitn_mut", [count_arg, _]) => {
@@ -3717,7 +3717,7 @@ fn check_methods<'tcx>(&self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
                 },
                 ("take", []) => needless_option_take::check(cx, expr, recv),
                 ("then", [arg]) => {
-                    if !meets_msrv(self.msrv, msrvs::BOOL_THEN_SOME) {
+                    if !self.msrv.meets(msrvs::BOOL_THEN_SOME) {
                         return;
                     }
                     unnecessary_lazy_eval::check(cx, expr, recv, arg, "then_some");
@@ -3760,7 +3760,7 @@ fn check_methods<'tcx>(&self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
                 },
                 ("unwrap_or_else", [u_arg]) => match method_call(recv) {
                     Some(("map", recv, [map_arg], _, _))
-                        if map_unwrap_or::check(cx, expr, recv, map_arg, u_arg, self.msrv) => {},
+                        if map_unwrap_or::check(cx, expr, recv, map_arg, u_arg, &self.msrv) => {},
                     _ => {
                         unwrap_or_else_default::check(cx, expr, recv, u_arg);
                         unnecessary_lazy_eval::check(cx, expr, recv, u_arg, "unwrap_or");
index e6eb64bcbde64ad0abd70e444e806a30ee51777d..3e33f9193374e3a4c80b838624a9cddc162c30ef 100644 (file)
@@ -1,13 +1,13 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::msrvs::{self, Msrv};
 use clippy_utils::source::snippet;
 use clippy_utils::ty::is_type_diagnostic_item;
-use clippy_utils::{match_def_path, meets_msrv, msrvs, path_to_local_id, paths, peel_blocks};
+use clippy_utils::{match_def_path, path_to_local_id, paths, peel_blocks};
 use if_chain::if_chain;
 use rustc_errors::Applicability;
 use rustc_hir as hir;
 use rustc_lint::LateContext;
 use rustc_middle::ty;
-use rustc_semver::RustcVersion;
 use rustc_span::sym;
 
 use super::OPTION_AS_REF_DEREF;
@@ -19,9 +19,9 @@ pub(super) fn check(
     as_ref_recv: &hir::Expr<'_>,
     map_arg: &hir::Expr<'_>,
     is_mut: bool,
-    msrv: Option<RustcVersion>,
+    msrv: &Msrv,
 ) {
-    if !meets_msrv(msrv, msrvs::OPTION_AS_DEREF) {
+    if !msrv.meets(msrvs::OPTION_AS_DEREF) {
         return;
     }
 
index 30421a6dd5afb458261b436cfc4d23dcce6ba57c..910ee14855e234d21507ff2ef01eb25061461bbb 100644 (file)
@@ -97,7 +97,7 @@ struct UnwrapVisitor<'a, 'tcx> {
 impl<'a, 'tcx> Visitor<'tcx> for UnwrapVisitor<'a, 'tcx> {
     type NestedFilter = nested_filter::All;
 
-    fn visit_path(&mut self, path: &'tcx Path<'_>, _id: HirId) {
+    fn visit_path(&mut self, path: &Path<'tcx>, _id: HirId) {
         self.identifiers.insert(ident(path));
         walk_path(self, path);
     }
@@ -116,7 +116,7 @@ struct MapExprVisitor<'a, 'tcx> {
 impl<'a, 'tcx> Visitor<'tcx> for MapExprVisitor<'a, 'tcx> {
     type NestedFilter = nested_filter::All;
 
-    fn visit_path(&mut self, path: &'tcx Path<'_>, _id: HirId) {
+    fn visit_path(&mut self, path: &Path<'tcx>, _id: HirId) {
         if self.identifiers.contains(&ident(path)) {
             self.found_identifier = true;
             return;
index 1acac59144cee8ce926daf8fdabfe5212918dae5..3c01ce1fecd3a28a161625b72d63331405ff852a 100644 (file)
@@ -1,9 +1,10 @@
 use clippy_utils::consts::{constant, Constant};
 use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then};
+use clippy_utils::msrvs::{self, Msrv};
 use clippy_utils::source::snippet_with_context;
 use clippy_utils::usage::local_used_after_expr;
 use clippy_utils::visitors::{for_each_expr_with_closures, Descend};
-use clippy_utils::{is_diag_item_method, match_def_path, meets_msrv, msrvs, path_to_local_id, paths};
+use clippy_utils::{is_diag_item_method, match_def_path, path_to_local_id, paths};
 use core::ops::ControlFlow;
 use if_chain::if_chain;
 use rustc_errors::Applicability;
@@ -12,7 +13,6 @@
 };
 use rustc_lint::LateContext;
 use rustc_middle::ty;
-use rustc_semver::RustcVersion;
 use rustc_span::{sym, Span, Symbol, SyntaxContext};
 
 use super::{MANUAL_SPLIT_ONCE, NEEDLESS_SPLITN};
@@ -24,7 +24,7 @@ pub(super) fn check(
     self_arg: &Expr<'_>,
     pat_arg: &Expr<'_>,
     count: u128,
-    msrv: Option<RustcVersion>,
+    msrv: &Msrv,
 ) {
     if count < 2 || !cx.typeck_results().expr_ty_adjusted(self_arg).peel_refs().is_str() {
         return;
@@ -34,7 +34,7 @@ pub(super) fn check(
         IterUsageKind::Nth(n) => count > n + 1,
         IterUsageKind::NextTuple => count > 2,
     };
-    let manual = count == 2 && meets_msrv(msrv, msrvs::STR_SPLIT_ONCE);
+    let manual = count == 2 && msrv.meets(msrvs::STR_SPLIT_ONCE);
 
     match parse_iter_usage(cx, expr.span.ctxt(), cx.tcx.hir().parent_iter(expr.hir_id)) {
         Some(usage) if needless(usage.kind) => lint_needless(cx, method_name, expr, self_arg, pat_arg),
index 7ff13b95626ba89b22d603caa7fbda300a0aaef1..9263f0519724bcaa58d30f45ef2c05d6569ec230 100644 (file)
@@ -1,13 +1,11 @@
 use super::implicit_clone::is_clone_like;
 use super::unnecessary_iter_cloned::{self, is_into_iter};
 use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::msrvs::{self, Msrv};
 use clippy_utils::source::snippet_opt;
 use clippy_utils::ty::{get_iterator_item_ty, implements_trait, is_copy, peel_mid_ty_refs};
 use clippy_utils::visitors::find_all_ret_expressions;
-use clippy_utils::{
-    fn_def_id, get_parent_expr, is_diag_item_method, is_diag_trait_item, return_ty,
-};
-use clippy_utils::{meets_msrv, msrvs};
+use clippy_utils::{fn_def_id, get_parent_expr, is_diag_item_method, is_diag_trait_item, return_ty};
 use rustc_errors::Applicability;
 use rustc_hir::{def_id::DefId, BorrowKind, Expr, ExprKind, ItemKind, Node};
 use rustc_hir_typeck::{FnCtxt, Inherited};
 use rustc_middle::mir::Mutability;
 use rustc_middle::ty::adjustment::{Adjust, Adjustment, OverloadedDeref};
 use rustc_middle::ty::subst::{GenericArg, GenericArgKind, SubstsRef};
-use rustc_middle::ty::EarlyBinder;
-use rustc_middle::ty::{self, Clause, ParamTy, PredicateKind, ProjectionPredicate, TraitPredicate, Ty};
-use rustc_semver::RustcVersion;
+use rustc_middle::ty::{self, Clause, EarlyBinder, ParamTy, PredicateKind, ProjectionPredicate, TraitPredicate, Ty};
 use rustc_span::{sym, Symbol};
-use rustc_trait_selection::traits::{
-    query::evaluate_obligation::InferCtxtExt as _, Obligation, ObligationCause,
-};
-use std::cmp::max;
+use rustc_trait_selection::traits::{query::evaluate_obligation::InferCtxtExt as _, Obligation, ObligationCause};
 
 use super::UNNECESSARY_TO_OWNED;
 
@@ -33,7 +26,7 @@ pub fn check<'tcx>(
     method_name: Symbol,
     receiver: &'tcx Expr<'_>,
     args: &'tcx [Expr<'_>],
-    msrv: Option<RustcVersion>,
+    msrv: &Msrv,
 ) {
     if_chain! {
         if let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id);
@@ -204,7 +197,7 @@ fn check_into_iter_call_arg(
     expr: &Expr<'_>,
     method_name: Symbol,
     receiver: &Expr<'_>,
-    msrv: Option<RustcVersion>,
+    msrv: &Msrv,
 ) -> bool {
     if_chain! {
         if let Some(parent) = get_parent_expr(cx, expr);
@@ -219,7 +212,7 @@ fn check_into_iter_call_arg(
             if unnecessary_iter_cloned::check_for_loop_iter(cx, parent, method_name, receiver, true) {
                 return true;
             }
-            let cloned_or_copied = if is_copy(cx, item_ty) && meets_msrv(msrv, msrvs::ITERATOR_COPIED) {
+            let cloned_or_copied = if is_copy(cx, item_ty) && msrv.meets(msrvs::ITERATOR_COPIED) {
                 "copied"
             } else {
                 "cloned"
@@ -267,11 +260,22 @@ fn check_other_call_arg<'tcx>(
         if let Some(as_ref_trait_id) = cx.tcx.get_diagnostic_item(sym::AsRef);
         if trait_predicate.def_id() == deref_trait_id || trait_predicate.def_id() == as_ref_trait_id;
         let receiver_ty = cx.typeck_results().expr_ty(receiver);
-        if can_change_type(cx, maybe_arg, receiver_ty);
         // We can't add an `&` when the trait is `Deref` because `Target = &T` won't match
         // `Target = T`.
-        if n_refs > 0 || is_copy(cx, receiver_ty) || trait_predicate.def_id() != deref_trait_id;
-        let n_refs = max(n_refs, usize::from(!is_copy(cx, receiver_ty)));
+        if let Some((n_refs, receiver_ty)) = if n_refs > 0 || is_copy(cx, receiver_ty) {
+            Some((n_refs, receiver_ty))
+        } else if trait_predicate.def_id() != deref_trait_id {
+            Some((1, cx.tcx.mk_ref(
+                cx.tcx.lifetimes.re_erased,
+                ty::TypeAndMut {
+                    ty: receiver_ty,
+                    mutbl: Mutability::Not,
+                },
+            )))
+        } else {
+            None
+        };
+        if can_change_type(cx, maybe_arg, receiver_ty);
         if let Some(receiver_snippet) = snippet_opt(cx, receiver.span);
         then {
             span_lint_and_sugg(
@@ -345,13 +349,13 @@ fn get_input_traits_and_projections<'tcx>(
                 if trait_predicate.trait_ref.self_ty() == input {
                     trait_predicates.push(trait_predicate);
                 }
-            }
+            },
             PredicateKind::Clause(Clause::Projection(projection_predicate)) => {
                 if projection_predicate.projection_ty.self_ty() == input {
                     projection_predicates.push(projection_predicate);
                 }
-            }
-            _ => {}
+            },
+            _ => {},
         }
     }
     (trait_predicates, projection_predicates)
@@ -382,14 +386,12 @@ fn can_change_type<'a>(cx: &LateContext<'a>, mut expr: &'a Expr<'a>, mut ty: Ty<
             Node::Expr(parent_expr) => {
                 if let Some((callee_def_id, call_substs, recv, call_args)) = get_callee_substs_and_args(cx, parent_expr)
                 {
-                    if Some(callee_def_id) == cx.tcx.lang_items().into_future_fn() {
-                        return false;
-                    }
-
                     let fn_sig = cx.tcx.fn_sig(callee_def_id).skip_binder();
                     if let Some(arg_index) = recv.into_iter().chain(call_args).position(|arg| arg.hir_id == expr.hir_id)
                         && let Some(param_ty) = fn_sig.inputs().get(arg_index)
                         && let ty::Param(ParamTy { index: param_index , ..}) = param_ty.kind()
+                        // https://github.com/rust-lang/rust-clippy/issues/9504 and https://github.com/rust-lang/rust-clippy/issues/10021
+                        && (*param_index as usize) < call_substs.len()
                     {
                         if fn_sig
                             .inputs()
@@ -403,10 +405,12 @@ fn can_change_type<'a>(cx: &LateContext<'a>, mut expr: &'a Expr<'a>, mut ty: Ty<
 
                         let mut trait_predicates = cx.tcx.param_env(callee_def_id)
                             .caller_bounds().iter().filter(|predicate| {
-                            if let PredicateKind::Clause(Clause::Trait(trait_predicate)) =  predicate.kind().skip_binder()
-                                && trait_predicate.trait_ref.self_ty() == *param_ty {
-                                    true
-                                } else {
+                            if let PredicateKind::Clause(Clause::Trait(trait_predicate))
+                                    = predicate.kind().skip_binder()
+                                && trait_predicate.trait_ref.self_ty() == *param_ty
+                            {
+                                true
+                            } else {
                                 false
                             }
                         });
@@ -466,12 +470,7 @@ fn is_cloned_or_copied(cx: &LateContext<'_>, method_name: Symbol, method_def_id:
 
 /// Returns true if the named method can be used to convert the receiver to its "owned"
 /// representation.
-fn is_to_owned_like<'a>(
-    cx: &LateContext<'a>,
-    call_expr: &Expr<'a>,
-    method_name: Symbol,
-    method_def_id: DefId,
-) -> bool {
+fn is_to_owned_like<'a>(cx: &LateContext<'a>, call_expr: &Expr<'a>, method_name: Symbol, method_def_id: DefId) -> bool {
     is_clone_like(cx, method_name.as_str(), method_def_id)
         || is_cow_into_owned(cx, method_name, method_def_id)
         || is_to_string_on_string_like(cx, call_expr, method_name, method_def_id)
index 71cc0d0a81cd2dd8bc909dd8780c79f857b919a0..5bc04bc17fb4f00bdf2cba1c1d9db4b08e8991a4 100644 (file)
@@ -1,9 +1,8 @@
 use clippy_utils::diagnostics::span_lint;
+use clippy_utils::msrvs::{self, Msrv};
 use clippy_utils::qualify_min_const_fn::is_min_const_fn;
 use clippy_utils::ty::has_drop;
-use clippy_utils::{
-    fn_has_unsatisfiable_preds, is_entrypoint_fn, is_from_proc_macro, meets_msrv, msrvs, trait_ref_of_method,
-};
+use clippy_utils::{fn_has_unsatisfiable_preds, is_entrypoint_fn, is_from_proc_macro, trait_ref_of_method};
 use rustc_hir as hir;
 use rustc_hir::def_id::CRATE_DEF_ID;
 use rustc_hir::intravisit::FnKind;
@@ -11,7 +10,6 @@
 use rustc_hir_analysis::hir_ty_to_ty;
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::lint::in_external_macro;
-use rustc_semver::RustcVersion;
 use rustc_session::{declare_tool_lint, impl_lint_pass};
 use rustc_span::Span;
 
 impl_lint_pass!(MissingConstForFn => [MISSING_CONST_FOR_FN]);
 
 pub struct MissingConstForFn {
-    msrv: Option<RustcVersion>,
+    msrv: Msrv,
 }
 
 impl MissingConstForFn {
     #[must_use]
-    pub fn new(msrv: Option<RustcVersion>) -> Self {
+    pub fn new(msrv: Msrv) -> Self {
         Self { msrv }
     }
 }
@@ -95,7 +93,7 @@ fn check_fn(
         span: Span,
         hir_id: HirId,
     ) {
-        if !meets_msrv(self.msrv, msrvs::CONST_IF_MATCH) {
+        if !self.msrv.meets(msrvs::CONST_IF_MATCH) {
             return;
         }
 
@@ -152,7 +150,7 @@ fn check_fn(
 
         let mir = cx.tcx.optimized_mir(def_id);
 
-        if let Err((span, err)) = is_min_const_fn(cx.tcx, mir, self.msrv) {
+        if let Err((span, err)) = is_min_const_fn(cx.tcx, mir, &self.msrv) {
             if cx.tcx.is_const_fn_raw(def_id.to_def_id()) {
                 cx.tcx.sess.span_err(span, err.as_ref());
             }
index 4712846939e6a0fcaae2a242895f7d9709988314..773174679dbdce618b244bfdfe9f5516d2eaaa0f 100644 (file)
@@ -66,35 +66,38 @@ fn check_crate(&mut self, cx: &LateContext<'_>) {
     }
 
     fn check_item(&mut self, cx: &LateContext<'_>, item: &Item<'_>) {
-        if_chain! {
-            if let ItemKind::Use(path, UseKind::Single) = &item.kind;
-            if let Res::Def(_, id) = path.res;
-            if let Some(name) = self.renames.get(&id);
-            // Remove semicolon since it is not present for nested imports
-            let span_without_semi = cx.sess().source_map().span_until_char(item.span, ';');
-            if let Some(snip) = snippet_opt(cx, span_without_semi);
-            if let Some(import) = match snip.split_once(" as ") {
-                None => Some(snip.as_str()),
-                Some((import, rename)) => {
-                    if rename.trim() == name.as_str() {
-                        None
-                    } else {
-                        Some(import.trim())
+        if let ItemKind::Use(path, UseKind::Single) = &item.kind {
+            for &res in &path.res {
+                if_chain! {
+                    if let Res::Def(_, id) = res;
+                    if let Some(name) = self.renames.get(&id);
+                    // Remove semicolon since it is not present for nested imports
+                    let span_without_semi = cx.sess().source_map().span_until_char(item.span, ';');
+                    if let Some(snip) = snippet_opt(cx, span_without_semi);
+                    if let Some(import) = match snip.split_once(" as ") {
+                        None => Some(snip.as_str()),
+                        Some((import, rename)) => {
+                            if rename.trim() == name.as_str() {
+                                None
+                            } else {
+                                Some(import.trim())
+                            }
+                        },
+                    };
+                    then {
+                        span_lint_and_sugg(
+                            cx,
+                            MISSING_ENFORCED_IMPORT_RENAMES,
+                            span_without_semi,
+                            "this import should be renamed",
+                            "try",
+                            format!(
+                                "{import} as {name}",
+                            ),
+                            Applicability::MachineApplicable,
+                        );
                     }
-                },
-            };
-            then {
-                span_lint_and_sugg(
-                    cx,
-                    MISSING_ENFORCED_IMPORT_RENAMES,
-                    span_without_semi,
-                    "this import should be renamed",
-                    "try",
-                    format!(
-                        "{import} as {name}",
-                    ),
-                    Applicability::MachineApplicable,
-                );
+                }
             }
         }
     }
index 75e12715458f4faf44f9605e6b22ce4470e36fb0..2f0b7ce16e51b77541bdee6927dea53c98bdb18e 100644 (file)
@@ -1,7 +1,9 @@
 use clippy_utils::diagnostics::{multispan_sugg, span_lint_and_then};
 use clippy_utils::ptr::get_spans;
 use clippy_utils::source::{snippet, snippet_opt};
-use clippy_utils::ty::{implements_trait, implements_trait_with_env, is_copy, is_type_diagnostic_item, is_type_lang_item};
+use clippy_utils::ty::{
+    implements_trait, implements_trait_with_env, is_copy, is_type_diagnostic_item, is_type_lang_item,
+};
 use clippy_utils::{get_trait_def_id, is_self, paths};
 use if_chain::if_chain;
 use rustc_ast::ast::Attribute;
@@ -124,7 +126,9 @@ fn check_fn(
             .filter_map(|obligation| {
                 // Note that we do not want to deal with qualified predicates here.
                 match obligation.predicate.kind().no_bound_vars() {
-                    Some(ty::PredicateKind::Clause(ty::Clause::Trait(pred))) if pred.def_id() != sized_trait => Some(pred),
+                    Some(ty::PredicateKind::Clause(ty::Clause::Trait(pred))) if pred.def_id() != sized_trait => {
+                        Some(pred)
+                    },
                     _ => None,
                 }
             })
index 819646bb6780e98099d405f0a1bd8993de003393..79c1ae4861e805d8edefa6f127ef200d1ea4a97d 100644 (file)
@@ -6,7 +6,8 @@
 use rustc_errors::Applicability;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::{is_range_literal, BinOpKind, BlockCheckMode, Expr, ExprKind, PatKind, Stmt, StmtKind, UnsafeSource};
-use rustc_lint::{LateContext, LateLintPass};
+use rustc_lint::{LateContext, LateLintPass, LintContext};
+use rustc_middle::lint::in_external_macro;
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use std::ops::Deref;
 
@@ -159,8 +160,11 @@ fn has_no_effect(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
 fn check_unnecessary_operation(cx: &LateContext<'_>, stmt: &Stmt<'_>) {
     if_chain! {
         if let StmtKind::Semi(expr) = stmt.kind;
+        let ctxt = stmt.span.ctxt();
+        if expr.span.ctxt() == ctxt;
         if let Some(reduced) = reduce_expression(cx, expr);
-        if !&reduced.iter().any(|e| e.span.from_expansion());
+        if !in_external_macro(cx.sess(), stmt.span);
+        if reduced.iter().all(|e| e.span.ctxt() == ctxt);
         then {
             if let ExprKind::Index(..) = &expr.kind {
                 let snippet = if let (Some(arr), Some(func)) =
index 92920bbad6e0a9a394ce2797f9e1a0ef90b635e7..e395ff54cb15a00f0693e6f8007f9d4ab1585aab 100644 (file)
@@ -490,7 +490,7 @@ fn check_fn_args<'cx, 'tcx: 'cx>(
                         ty_name: name.ident.name,
                         method_renames,
                         ref_prefix: RefPrefix {
-                            lt: lt.clone(),
+                            lt: *lt,
                             mutability,
                         },
                         deref_ty,
@@ -693,9 +693,10 @@ fn matches_preds<'tcx>(
             cx.tcx,
             ObligationCause::dummy(),
             cx.param_env,
-            cx.tcx.mk_predicate(Binder::dummy(
-                PredicateKind::Clause(Clause::Projection(p.with_self_ty(cx.tcx, ty))),
-            )),
+            cx.tcx
+                .mk_predicate(Binder::dummy(PredicateKind::Clause(Clause::Projection(
+                    p.with_self_ty(cx.tcx, ty),
+                )))),
         )),
         ExistentialPredicate::AutoTrait(p) => infcx
             .type_implements_trait(p, [ty], cx.param_env)
index c6fbb5e805ab2812a6da2d7db80b5ca4ec7d834d..0a1b9d173cf9409ee453de6f7085ac14b9f8ab89 100644 (file)
@@ -1,16 +1,16 @@
 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::msrvs::{self, Msrv};
 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::{get_parent_expr, in_constant, is_integer_const, path_to_local};
 use if_chain::if_chain;
 use rustc_ast::ast::RangeLimits;
 use rustc_errors::Applicability;
 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 std::cmp::Ordering;
 }
 
 pub struct Ranges {
-    msrv: Option<RustcVersion>,
+    msrv: Msrv,
 }
 
 impl Ranges {
     #[must_use]
-    pub fn new(msrv: Option<RustcVersion>) -> Self {
+    pub fn new(msrv: Msrv) -> Self {
         Self { msrv }
     }
 }
@@ -181,7 +181,7 @@ pub fn new(msrv: Option<RustcVersion>) -> Self {
 impl<'tcx> LateLintPass<'tcx> for Ranges {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
         if let ExprKind::Binary(ref op, l, r) = expr.kind {
-            if meets_msrv(self.msrv, msrvs::RANGE_CONTAINS) {
+            if self.msrv.meets(msrvs::RANGE_CONTAINS) {
                 check_possible_range_contains(cx, op.node, l, r, expr, expr.span);
             }
         }
index 8e675d34a183698b970e86e0fca4f5dd27c1903d..2a42e73488f1905c4b98cb45ea1fee522baaf567 100644 (file)
@@ -81,8 +81,8 @@ fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &ast::Expr) {
                         "try not to call a closure in the expression where it is declared",
                         |diag| {
                             if fn_decl.inputs.is_empty() {
-                                let app = Applicability::MachineApplicable;
-                                let mut hint = Sugg::ast(cx, body, "..");
+                                let mut app = Applicability::MachineApplicable;
+                                let mut hint = Sugg::ast(cx, body, "..", closure.span.ctxt(), &mut app);
 
                                 if asyncness.is_async() {
                                     // `async x` is a syntax error, so it becomes `async { x }`
index 40b03068f6c772059167ff6814824d1d0846e33e..61bff4a0e38d842194be07d7d8bd960436aed2fe 100644 (file)
@@ -1,10 +1,9 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::{meets_msrv, msrvs};
+use clippy_utils::msrvs::{self, Msrv};
 use rustc_ast::ast::{Expr, ExprKind};
 use rustc_errors::Applicability;
 use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
 use rustc_middle::lint::in_external_macro;
-use rustc_semver::RustcVersion;
 use rustc_session::{declare_tool_lint, impl_lint_pass};
 
 declare_clippy_lint! {
 }
 
 pub struct RedundantFieldNames {
-    msrv: Option<RustcVersion>,
+    msrv: Msrv,
 }
 
 impl RedundantFieldNames {
     #[must_use]
-    pub fn new(msrv: Option<RustcVersion>) -> Self {
+    pub fn new(msrv: Msrv) -> Self {
         Self { msrv }
     }
 }
@@ -51,7 +50,7 @@ pub fn new(msrv: Option<RustcVersion>) -> Self {
 
 impl EarlyLintPass for RedundantFieldNames {
     fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) {
-        if !meets_msrv(self.msrv, msrvs::FIELD_INIT_SHORTHAND) {
+        if !self.msrv.meets(msrvs::FIELD_INIT_SHORTHAND) {
             return;
         }
 
index 833dc4913b46922a215653311abb91bb6da5c745..d612d249c2f000ab3c869952f1806ff491ac2450 100644 (file)
@@ -84,7 +84,7 @@ fn check_item_post(&mut self, _cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) {
 
 fn is_not_macro_export<'tcx>(item: &'tcx Item<'tcx>) -> bool {
     if let ItemKind::Use(path, _) = item.kind {
-        if let Res::Def(DefKind::Macro(MacroKind::Bang), _) = path.res {
+        if path.res.iter().all(|res| matches!(res, Res::Def(DefKind::Macro(MacroKind::Bang), _))) {
             return false;
         }
     } else if let ItemKind::Macro(..) = item.kind {
index 60ba62c4a4332532f2b42d46732005c7b3a10174..3aa2490bc44e018fa32371b1f94e0c69a46e4892 100644 (file)
@@ -1,10 +1,9 @@
 use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::msrvs::{self, Msrv};
 use clippy_utils::source::snippet;
-use clippy_utils::{meets_msrv, msrvs};
 use rustc_ast::ast::{Item, ItemKind, Ty, TyKind};
 use rustc_errors::Applicability;
 use rustc_lint::{EarlyContext, EarlyLintPass};
-use rustc_semver::RustcVersion;
 use rustc_session::{declare_tool_lint, impl_lint_pass};
 
 declare_clippy_lint! {
 }
 
 pub struct RedundantStaticLifetimes {
-    msrv: Option<RustcVersion>,
+    msrv: Msrv,
 }
 
 impl RedundantStaticLifetimes {
     #[must_use]
-    pub fn new(msrv: Option<RustcVersion>) -> Self {
+    pub fn new(msrv: Msrv) -> Self {
         Self { msrv }
     }
 }
@@ -96,7 +95,7 @@ fn visit_type(ty: &Ty, cx: &EarlyContext<'_>, reason: &str) {
 
 impl EarlyLintPass for RedundantStaticLifetimes {
     fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) {
-        if !meets_msrv(self.msrv, msrvs::STATIC_IN_CONST) {
+        if !self.msrv.meets(msrvs::STATIC_IN_CONST) {
             return;
         }
 
index 2b2a41d160117a5f781cf7d389df8ad550e353d4..81143d7799ea8aa585f2e023b3cb9d3560dfd22f 100644 (file)
@@ -12,6 +12,7 @@
 use rustc_middle::ty::subst::GenericArgKind;
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::source_map::Span;
+use rustc_span::{BytePos, Pos};
 
 declare_clippy_lint! {
     /// ### What it does
@@ -209,13 +210,14 @@ fn check_final_expr<'tcx>(
             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(
-                        cx,
-                        peeled_drop_expr.span,
-                        semi_spans,
-                        inner.as_ref().map(|i| i.span),
-                        replacement,
-                    );
+                    // check if expr return nothing
+                    let ret_span = if inner.is_none() && replacement == RetReplacement::Empty {
+                        extend_span_to_previous_non_ws(cx, peeled_drop_expr.span)
+                    } else {
+                        peeled_drop_expr.span
+                    };
+
+                    emit_return_lint(cx, ret_span, semi_spans, inner.as_ref().map(|i| i.span), replacement);
                 }
             }
         },
@@ -289,3 +291,16 @@ fn last_statement_borrows<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>)
     })
     .is_some()
 }
+
+// Go backwards while encountering whitespace and extend the given Span to that point.
+fn extend_span_to_previous_non_ws(cx: &LateContext<'_>, sp: Span) -> Span {
+    if let Ok(prev_source) = cx.sess().source_map().span_to_prev_source(sp) {
+        let ws = [' ', '\t', '\n'];
+        if let Some(non_ws_pos) = prev_source.rfind(|c| !ws.contains(&c)) {
+            let len = prev_source.len() - non_ws_pos - 1;
+            return sp.with_lo(sp.lo() - BytePos::from_usize(len));
+        }
+    }
+
+    sp
+}
index 2036e85db7e8ca73f5f73e80cbfa570498016131..d46f6a6352c63ead2b1418c911e887ce0eaefe4b 100644 (file)
@@ -149,7 +149,7 @@ fn track_uses(
 
                 // keep track of `use some_module;` usages
                 if segments.len() == 1 {
-                    if let UseTreeKind::Simple(None, _, _) = use_tree.kind {
+                    if let UseTreeKind::Simple(None) = use_tree.kind {
                         let name = segments[0].ident.name;
                         if !macros.contains(&name) {
                             single_use_usages.push(SingleUse {
@@ -169,7 +169,7 @@ fn track_uses(
                         for tree in trees {
                             let segments = &tree.0.prefix.segments;
                             if segments.len() == 1 {
-                                if let UseTreeKind::Simple(None, _, _) = tree.0.kind {
+                                if let UseTreeKind::Simple(None) = tree.0.kind {
                                     let name = segments[0].ident.name;
                                     if !macros.contains(&name) {
                                         single_use_usages.push(SingleUse {
index 424a6e9264e4b96680b6e4a09cfab81e2a36083f..83e651aba8e89b15ed99db9dfcf768afece1431f 100644 (file)
 mod wrong_transmute;
 
 use clippy_utils::in_constant;
+use clippy_utils::msrvs::Msrv;
 use if_chain::if_chain;
 use rustc_hir::{Expr, ExprKind, QPath};
 use rustc_lint::{LateContext, LateLintPass};
-use rustc_semver::RustcVersion;
 use rustc_session::{declare_tool_lint, impl_lint_pass};
 use rustc_span::symbol::sym;
 
 }
 
 pub struct Transmute {
-    msrv: Option<RustcVersion>,
+    msrv: Msrv,
 }
 impl_lint_pass!(Transmute => [
     CROSSPOINTER_TRANSMUTE,
@@ -431,7 +431,7 @@ pub struct Transmute {
 ]);
 impl Transmute {
     #[must_use]
-    pub fn new(msrv: Option<RustcVersion>) -> Self {
+    pub fn new(msrv: Msrv) -> Self {
         Self { msrv }
     }
 }
@@ -461,7 +461,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_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)
                     | transmute_ptr_to_ptr::check(cx, e, from_ty, to_ty, arg)
index 12d0b866e1c9bbcada978b4d065557fea93080d8..3dde4eee67179fd9a394b10d5799b1d93ca04748 100644 (file)
@@ -1,12 +1,12 @@
 use super::TRANSMUTE_PTR_TO_REF;
 use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::msrvs::{self, Msrv};
 use clippy_utils::source::snippet_with_applicability;
-use clippy_utils::{meets_msrv, msrvs, sugg};
+use clippy_utils::sugg;
 use rustc_errors::Applicability;
 use rustc_hir::{self as hir, Expr, GenericArg, Mutability, Path, TyKind};
 use rustc_lint::LateContext;
 use rustc_middle::ty::{self, Ty, TypeVisitable};
-use rustc_semver::RustcVersion;
 
 /// Checks for `transmute_ptr_to_ref` lint.
 /// Returns `true` if it's triggered, otherwise returns `false`.
@@ -17,7 +17,7 @@ pub(super) fn check<'tcx>(
     to_ty: Ty<'tcx>,
     arg: &'tcx Expr<'_>,
     path: &'tcx Path<'_>,
-    msrv: Option<RustcVersion>,
+    msrv: &Msrv,
 ) -> bool {
     match (&from_ty.kind(), &to_ty.kind()) {
         (ty::RawPtr(from_ptr_ty), ty::Ref(_, to_ref_ty, mutbl)) => {
@@ -37,7 +37,7 @@ pub(super) fn check<'tcx>(
 
                     let sugg = if let Some(ty) = get_explicit_type(path) {
                         let ty_snip = snippet_with_applicability(cx, ty.span, "..", &mut app);
-                        if meets_msrv(msrv, msrvs::POINTER_CAST) {
+                        if msrv.meets(msrvs::POINTER_CAST) {
                             format!("{deref}{}.cast::<{ty_snip}>()", arg.maybe_par())
                         } else if from_ptr_ty.has_erased_regions() {
                             sugg::make_unop(deref, arg.as_ty(format!("{cast} () as {cast} {ty_snip}"))).to_string()
@@ -46,7 +46,7 @@ pub(super) fn check<'tcx>(
                         }
                     } else if from_ptr_ty.ty == *to_ref_ty {
                         if from_ptr_ty.has_erased_regions() {
-                            if meets_msrv(msrv, msrvs::POINTER_CAST) {
+                            if msrv.meets(msrvs::POINTER_CAST) {
                                 format!("{deref}{}.cast::<{to_ref_ty}>()", arg.maybe_par())
                             } else {
                                 sugg::make_unop(deref, arg.as_ty(format!("{cast} () as {cast} {to_ref_ty}")))
index e8f15a4447352a9cedd66892e34831cb089a800f..2e1b6d8d4ea7f743a862d8088ec8554b28ba913d 100644 (file)
@@ -1,6 +1,10 @@
+use std::ops::ControlFlow;
+
 use clippy_utils::diagnostics::span_lint_and_help;
 use clippy_utils::source::walk_span_to_context;
+use clippy_utils::visitors::{for_each_expr_with_closures, Descend};
 use clippy_utils::{get_parent_node, is_lint_allowed};
+use hir::HirId;
 use rustc_data_structures::sync::Lrc;
 use rustc_hir as hir;
 use rustc_hir::{Block, BlockCheckMode, ItemKind, Node, UnsafeSource};
     restriction,
     "creating an unsafe block without explaining why it is safe"
 }
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for `// SAFETY: ` comments on safe code.
+    ///
+    /// ### Why is this bad?
+    /// Safe code has no safety requirements, so there is no need to
+    /// describe safety invariants.
+    ///
+    /// ### Example
+    /// ```rust
+    /// use std::ptr::NonNull;
+    /// let a = &mut 42;
+    ///
+    /// // SAFETY: references are guaranteed to be non-null.
+    /// let ptr = NonNull::new(a).unwrap();
+    /// ```
+    /// Use instead:
+    /// ```rust
+    /// use std::ptr::NonNull;
+    /// let a = &mut 42;
+    ///
+    /// let ptr = NonNull::new(a).unwrap();
+    /// ```
+    #[clippy::version = "1.67.0"]
+    pub UNNECESSARY_SAFETY_COMMENT,
+    restriction,
+    "annotating safe code with a safety comment"
+}
 
-declare_lint_pass!(UndocumentedUnsafeBlocks => [UNDOCUMENTED_UNSAFE_BLOCKS]);
+declare_lint_pass!(UndocumentedUnsafeBlocks => [UNDOCUMENTED_UNSAFE_BLOCKS, UNNECESSARY_SAFETY_COMMENT]);
 
-impl LateLintPass<'_> for UndocumentedUnsafeBlocks {
-    fn check_block(&mut self, cx: &LateContext<'_>, block: &'_ Block<'_>) {
+impl<'tcx> LateLintPass<'tcx> for UndocumentedUnsafeBlocks {
+    fn check_block(&mut self, cx: &LateContext<'tcx>, block: &'tcx Block<'tcx>) {
         if block.rules == BlockCheckMode::UnsafeBlock(UnsafeSource::UserProvided)
             && !in_external_macro(cx.tcx.sess, block.span)
             && !is_lint_allowed(cx, UNDOCUMENTED_UNSAFE_BLOCKS, block.hir_id)
@@ -87,35 +119,175 @@ fn check_block(&mut self, cx: &LateContext<'_>, block: &'_ Block<'_>) {
                 "consider adding a safety comment on the preceding line",
             );
         }
+
+        if let Some(tail) = block.expr
+            && !is_lint_allowed(cx, UNNECESSARY_SAFETY_COMMENT, tail.hir_id)
+            && !in_external_macro(cx.tcx.sess, tail.span)
+            && let HasSafetyComment::Yes(pos) = stmt_has_safety_comment(cx, tail.span, tail.hir_id)
+            && let Some(help_span) = expr_has_unnecessary_safety_comment(cx, tail, pos)
+        {
+            span_lint_and_help(
+                cx,
+                UNNECESSARY_SAFETY_COMMENT,
+                tail.span,
+                "expression has unnecessary safety comment",
+                Some(help_span),
+                "consider removing the safety comment",
+            );
+        }
     }
 
-    fn check_item(&mut self, cx: &LateContext<'_>, item: &hir::Item<'_>) {
-        if let hir::ItemKind::Impl(imple) = item.kind
-            && imple.unsafety == hir::Unsafety::Unsafe
-            && !in_external_macro(cx.tcx.sess, item.span)
-            && !is_lint_allowed(cx, UNDOCUMENTED_UNSAFE_BLOCKS, item.hir_id())
-            && !is_unsafe_from_proc_macro(cx, item.span)
-            && !item_has_safety_comment(cx, item)
+    fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &hir::Stmt<'tcx>) {
+        let (
+            hir::StmtKind::Local(&hir::Local { init: Some(expr), .. })
+            | hir::StmtKind::Expr(expr)
+            | hir::StmtKind::Semi(expr)
+        ) = stmt.kind else { return };
+        if !is_lint_allowed(cx, UNNECESSARY_SAFETY_COMMENT, stmt.hir_id)
+            && !in_external_macro(cx.tcx.sess, stmt.span)
+            && let HasSafetyComment::Yes(pos) = stmt_has_safety_comment(cx, stmt.span, stmt.hir_id)
+            && let Some(help_span) = expr_has_unnecessary_safety_comment(cx, expr, pos)
         {
+            span_lint_and_help(
+                cx,
+                UNNECESSARY_SAFETY_COMMENT,
+                stmt.span,
+                "statement has unnecessary safety comment",
+                Some(help_span),
+                "consider removing the safety comment",
+            );
+        }
+    }
+
+    fn check_item(&mut self, cx: &LateContext<'_>, item: &hir::Item<'_>) {
+        if in_external_macro(cx.tcx.sess, item.span) {
+            return;
+        }
+
+        let mk_spans = |pos: BytePos| {
             let source_map = cx.tcx.sess.source_map();
+            let span = Span::new(pos, pos, SyntaxContext::root(), None);
+            let help_span = source_map.span_extend_to_next_char(span, '\n', true);
             let span = if source_map.is_multiline(item.span) {
                 source_map.span_until_char(item.span, '\n')
             } else {
                 item.span
             };
+            (span, help_span)
+        };
 
-            span_lint_and_help(
-                cx,
-                UNDOCUMENTED_UNSAFE_BLOCKS,
-                span,
-                "unsafe impl missing a safety comment",
-                None,
-                "consider adding a safety comment on the preceding line",
-            );
+        let item_has_safety_comment = item_has_safety_comment(cx, item);
+        match (&item.kind, item_has_safety_comment) {
+            // lint unsafe impl without safety comment
+            (hir::ItemKind::Impl(impl_), HasSafetyComment::No) if impl_.unsafety == hir::Unsafety::Unsafe => {
+                if !is_lint_allowed(cx, UNDOCUMENTED_UNSAFE_BLOCKS, item.hir_id())
+                    && !is_unsafe_from_proc_macro(cx, item.span)
+                {
+                    let source_map = cx.tcx.sess.source_map();
+                    let span = if source_map.is_multiline(item.span) {
+                        source_map.span_until_char(item.span, '\n')
+                    } else {
+                        item.span
+                    };
+
+                    span_lint_and_help(
+                        cx,
+                        UNDOCUMENTED_UNSAFE_BLOCKS,
+                        span,
+                        "unsafe impl missing a safety comment",
+                        None,
+                        "consider adding a safety comment on the preceding line",
+                    );
+                }
+            },
+            // lint safe impl with unnecessary safety comment
+            (hir::ItemKind::Impl(impl_), HasSafetyComment::Yes(pos)) if impl_.unsafety == hir::Unsafety::Normal => {
+                if !is_lint_allowed(cx, UNNECESSARY_SAFETY_COMMENT, item.hir_id()) {
+                    let (span, help_span) = mk_spans(pos);
+
+                    span_lint_and_help(
+                        cx,
+                        UNNECESSARY_SAFETY_COMMENT,
+                        span,
+                        "impl has unnecessary safety comment",
+                        Some(help_span),
+                        "consider removing the safety comment",
+                    );
+                }
+            },
+            (hir::ItemKind::Impl(_), _) => {},
+            // const and static items only need a safety comment if their body is an unsafe block, lint otherwise
+            (&hir::ItemKind::Const(.., body) | &hir::ItemKind::Static(.., body), HasSafetyComment::Yes(pos)) => {
+                if !is_lint_allowed(cx, UNNECESSARY_SAFETY_COMMENT, body.hir_id) {
+                    let body = cx.tcx.hir().body(body);
+                    if !matches!(
+                        body.value.kind, hir::ExprKind::Block(block, _)
+                        if block.rules == BlockCheckMode::UnsafeBlock(UnsafeSource::UserProvided)
+                    ) {
+                        let (span, help_span) = mk_spans(pos);
+
+                        span_lint_and_help(
+                            cx,
+                            UNNECESSARY_SAFETY_COMMENT,
+                            span,
+                            &format!("{} has unnecessary safety comment", item.kind.descr()),
+                            Some(help_span),
+                            "consider removing the safety comment",
+                        );
+                    }
+                }
+            },
+            // Aside from unsafe impls and consts/statics with an unsafe block, items in general
+            // do not have safety invariants that need to be documented, so lint those.
+            (_, HasSafetyComment::Yes(pos)) => {
+                if !is_lint_allowed(cx, UNNECESSARY_SAFETY_COMMENT, item.hir_id()) {
+                    let (span, help_span) = mk_spans(pos);
+
+                    span_lint_and_help(
+                        cx,
+                        UNNECESSARY_SAFETY_COMMENT,
+                        span,
+                        &format!("{} has unnecessary safety comment", item.kind.descr()),
+                        Some(help_span),
+                        "consider removing the safety comment",
+                    );
+                }
+            },
+            _ => (),
         }
     }
 }
 
+fn expr_has_unnecessary_safety_comment<'tcx>(
+    cx: &LateContext<'tcx>,
+    expr: &'tcx hir::Expr<'tcx>,
+    comment_pos: BytePos,
+) -> Option<Span> {
+    // this should roughly be the reverse of `block_parents_have_safety_comment`
+    if for_each_expr_with_closures(cx, expr, |expr| match expr.kind {
+        hir::ExprKind::Block(
+            Block {
+                rules: BlockCheckMode::UnsafeBlock(UnsafeSource::UserProvided),
+                ..
+            },
+            _,
+        ) => ControlFlow::Break(()),
+        // statements will be handled by check_stmt itself again
+        hir::ExprKind::Block(..) => ControlFlow::Continue(Descend::No),
+        _ => ControlFlow::Continue(Descend::Yes),
+    })
+    .is_some()
+    {
+        return None;
+    }
+
+    let source_map = cx.tcx.sess.source_map();
+    let span = Span::new(comment_pos, comment_pos, SyntaxContext::root(), None);
+    let help_span = source_map.span_extend_to_next_char(span, '\n', true);
+
+    Some(help_span)
+}
+
 fn is_unsafe_from_proc_macro(cx: &LateContext<'_>, span: Span) -> bool {
     let source_map = cx.sess().source_map();
     let file_pos = source_map.lookup_byte_offset(span.lo());
@@ -170,85 +342,134 @@ fn block_has_safety_comment(cx: &LateContext<'_>, span: Span) -> bool {
     // won't work. This is to avoid dealing with where such a comment should be place relative to
     // attributes and doc comments.
 
-    span_from_macro_expansion_has_safety_comment(cx, span) || span_in_body_has_safety_comment(cx, span)
+    matches!(
+        span_from_macro_expansion_has_safety_comment(cx, span),
+        HasSafetyComment::Yes(_)
+    ) || span_in_body_has_safety_comment(cx, span)
+}
+
+enum HasSafetyComment {
+    Yes(BytePos),
+    No,
+    Maybe,
 }
 
 /// Checks if the lines immediately preceding the item contain a safety comment.
 #[allow(clippy::collapsible_match)]
-fn item_has_safety_comment(cx: &LateContext<'_>, item: &hir::Item<'_>) -> bool {
-    if span_from_macro_expansion_has_safety_comment(cx, item.span) {
-        return true;
+fn item_has_safety_comment(cx: &LateContext<'_>, item: &hir::Item<'_>) -> HasSafetyComment {
+    match span_from_macro_expansion_has_safety_comment(cx, item.span) {
+        HasSafetyComment::Maybe => (),
+        has_safety_comment => return has_safety_comment,
     }
 
-    if item.span.ctxt() == SyntaxContext::root() {
-        if let Some(parent_node) = get_parent_node(cx.tcx, item.hir_id()) {
-            let comment_start = match parent_node {
-                Node::Crate(parent_mod) => {
-                    comment_start_before_impl_in_mod(cx, parent_mod, parent_mod.spans.inner_span, item)
-                },
-                Node::Item(parent_item) => {
-                    if let ItemKind::Mod(parent_mod) = &parent_item.kind {
-                        comment_start_before_impl_in_mod(cx, parent_mod, parent_item.span, item)
-                    } else {
-                        // Doesn't support impls in this position. Pretend a comment was found.
-                        return true;
-                    }
-                },
-                Node::Stmt(stmt) => {
-                    if let Some(stmt_parent) = get_parent_node(cx.tcx, stmt.hir_id) {
-                        match stmt_parent {
-                            Node::Block(block) => walk_span_to_context(block.span, SyntaxContext::root()).map(Span::lo),
-                            _ => {
-                                // Doesn't support impls in this position. Pretend a comment was found.
-                                return true;
-                            },
-                        }
-                    } else {
-                        // Problem getting the parent node. Pretend a comment was found.
-                        return true;
-                    }
-                },
-                _ => {
+    if item.span.ctxt() != SyntaxContext::root() {
+        return HasSafetyComment::No;
+    }
+    if let Some(parent_node) = get_parent_node(cx.tcx, item.hir_id()) {
+        let comment_start = match parent_node {
+            Node::Crate(parent_mod) => {
+                comment_start_before_item_in_mod(cx, parent_mod, parent_mod.spans.inner_span, item)
+            },
+            Node::Item(parent_item) => {
+                if let ItemKind::Mod(parent_mod) = &parent_item.kind {
+                    comment_start_before_item_in_mod(cx, parent_mod, parent_item.span, item)
+                } else {
                     // Doesn't support impls in this position. Pretend a comment was found.
-                    return true;
-                },
-            };
+                    return HasSafetyComment::Maybe;
+                }
+            },
+            Node::Stmt(stmt) => {
+                if let Some(Node::Block(block)) = get_parent_node(cx.tcx, stmt.hir_id) {
+                    walk_span_to_context(block.span, SyntaxContext::root()).map(Span::lo)
+                } else {
+                    // Problem getting the parent node. Pretend a comment was found.
+                    return HasSafetyComment::Maybe;
+                }
+            },
+            _ => {
+                // Doesn't support impls in this position. Pretend a comment was found.
+                return HasSafetyComment::Maybe;
+            },
+        };
 
-            let source_map = cx.sess().source_map();
-            if let Some(comment_start) = comment_start
-                && let Ok(unsafe_line) = source_map.lookup_line(item.span.lo())
-                && let Ok(comment_start_line) = source_map.lookup_line(comment_start)
-                && Lrc::ptr_eq(&unsafe_line.sf, &comment_start_line.sf)
-                && let Some(src) = unsafe_line.sf.src.as_deref()
-            {
-                unsafe_line.sf.lines(|lines| {
-                    comment_start_line.line < unsafe_line.line && text_has_safety_comment(
+        let source_map = cx.sess().source_map();
+        if let Some(comment_start) = comment_start
+            && let Ok(unsafe_line) = source_map.lookup_line(item.span.lo())
+            && let Ok(comment_start_line) = source_map.lookup_line(comment_start)
+            && Lrc::ptr_eq(&unsafe_line.sf, &comment_start_line.sf)
+            && let Some(src) = unsafe_line.sf.src.as_deref()
+        {
+            return unsafe_line.sf.lines(|lines| {
+                if comment_start_line.line >= unsafe_line.line {
+                    HasSafetyComment::No
+                } else {
+                    match text_has_safety_comment(
                         src,
                         &lines[comment_start_line.line + 1..=unsafe_line.line],
                         unsafe_line.sf.start_pos.to_usize(),
-                    )
-                })
-            } else {
-                // Problem getting source text. Pretend a comment was found.
-                true
-            }
-        } else {
-            // No parent node. Pretend a comment was found.
-            true
+                    ) {
+                        Some(b) => HasSafetyComment::Yes(b),
+                        None => HasSafetyComment::No,
+                    }
+                }
+            });
+        }
+    }
+    HasSafetyComment::Maybe
+}
+
+/// Checks if the lines immediately preceding the item contain a safety comment.
+#[allow(clippy::collapsible_match)]
+fn stmt_has_safety_comment(cx: &LateContext<'_>, span: Span, hir_id: HirId) -> HasSafetyComment {
+    match span_from_macro_expansion_has_safety_comment(cx, span) {
+        HasSafetyComment::Maybe => (),
+        has_safety_comment => return has_safety_comment,
+    }
+
+    if span.ctxt() != SyntaxContext::root() {
+        return HasSafetyComment::No;
+    }
+
+    if let Some(parent_node) = get_parent_node(cx.tcx, hir_id) {
+        let comment_start = match parent_node {
+            Node::Block(block) => walk_span_to_context(block.span, SyntaxContext::root()).map(Span::lo),
+            _ => return HasSafetyComment::Maybe,
+        };
+
+        let source_map = cx.sess().source_map();
+        if let Some(comment_start) = comment_start
+            && let Ok(unsafe_line) = source_map.lookup_line(span.lo())
+            && let Ok(comment_start_line) = source_map.lookup_line(comment_start)
+            && Lrc::ptr_eq(&unsafe_line.sf, &comment_start_line.sf)
+            && let Some(src) = unsafe_line.sf.src.as_deref()
+        {
+            return unsafe_line.sf.lines(|lines| {
+                if comment_start_line.line >= unsafe_line.line {
+                    HasSafetyComment::No
+                } else {
+                    match text_has_safety_comment(
+                        src,
+                        &lines[comment_start_line.line + 1..=unsafe_line.line],
+                        unsafe_line.sf.start_pos.to_usize(),
+                    ) {
+                        Some(b) => HasSafetyComment::Yes(b),
+                        None => HasSafetyComment::No,
+                    }
+                }
+            });
         }
-    } else {
-        false
     }
+    HasSafetyComment::Maybe
 }
 
-fn comment_start_before_impl_in_mod(
+fn comment_start_before_item_in_mod(
     cx: &LateContext<'_>,
     parent_mod: &hir::Mod<'_>,
     parent_mod_span: Span,
-    imple: &hir::Item<'_>,
+    item: &hir::Item<'_>,
 ) -> Option<BytePos> {
     parent_mod.item_ids.iter().enumerate().find_map(|(idx, item_id)| {
-        if *item_id == imple.item_id() {
+        if *item_id == item.item_id() {
             if idx == 0 {
                 // mod A { /* comment */ unsafe impl T {} ... }
                 // ^------------------------------------------^ returns the start of this span
@@ -270,11 +491,11 @@ fn comment_start_before_impl_in_mod(
     })
 }
 
-fn span_from_macro_expansion_has_safety_comment(cx: &LateContext<'_>, span: Span) -> bool {
+fn span_from_macro_expansion_has_safety_comment(cx: &LateContext<'_>, span: Span) -> HasSafetyComment {
     let source_map = cx.sess().source_map();
     let ctxt = span.ctxt();
     if ctxt == SyntaxContext::root() {
-        false
+        HasSafetyComment::Maybe
     } else {
         // From a macro expansion. Get the text from the start of the macro declaration to start of the
         // unsafe block.
@@ -286,15 +507,22 @@ fn span_from_macro_expansion_has_safety_comment(cx: &LateContext<'_>, span: Span
             && let Some(src) = unsafe_line.sf.src.as_deref()
         {
             unsafe_line.sf.lines(|lines| {
-                macro_line.line < unsafe_line.line && text_has_safety_comment(
-                    src,
-                    &lines[macro_line.line + 1..=unsafe_line.line],
-                    unsafe_line.sf.start_pos.to_usize(),
-                )
+                if macro_line.line < unsafe_line.line {
+                    match text_has_safety_comment(
+                        src,
+                        &lines[macro_line.line + 1..=unsafe_line.line],
+                        unsafe_line.sf.start_pos.to_usize(),
+                    ) {
+                        Some(b) => HasSafetyComment::Yes(b),
+                        None => HasSafetyComment::No,
+                    }
+                } else {
+                    HasSafetyComment::No
+                }
             })
         } else {
             // Problem getting source text. Pretend a comment was found.
-            true
+            HasSafetyComment::Maybe
         }
     }
 }
@@ -333,7 +561,7 @@ fn span_in_body_has_safety_comment(cx: &LateContext<'_>, span: Span) -> bool {
                     src,
                     &lines[body_line.line + 1..=unsafe_line.line],
                     unsafe_line.sf.start_pos.to_usize(),
-                )
+                ).is_some()
             })
         } else {
             // Problem getting source text. Pretend a comment was found.
@@ -345,30 +573,34 @@ fn span_in_body_has_safety_comment(cx: &LateContext<'_>, span: Span) -> bool {
 }
 
 /// Checks if the given text has a safety comment for the immediately proceeding line.
-fn text_has_safety_comment(src: &str, line_starts: &[BytePos], offset: usize) -> bool {
+fn text_has_safety_comment(src: &str, line_starts: &[BytePos], offset: usize) -> Option<BytePos> {
     let mut lines = line_starts
         .array_windows::<2>()
         .rev()
         .map_while(|[start, end]| {
             let start = start.to_usize() - offset;
             let end = end.to_usize() - offset;
-            src.get(start..end).map(|text| (start, text.trim_start()))
+            let text = src.get(start..end)?;
+            let trimmed = text.trim_start();
+            Some((start + (text.len() - trimmed.len()), trimmed))
         })
         .filter(|(_, text)| !text.is_empty());
 
     let Some((line_start, line)) = lines.next() else {
-        return false;
+        return None;
     };
     // Check for a sequence of line comments.
     if line.starts_with("//") {
-        let mut line = line;
+        let (mut line, mut line_start) = (line, line_start);
         loop {
             if line.to_ascii_uppercase().contains("SAFETY:") {
-                return true;
+                return Some(BytePos(
+                    u32::try_from(line_start).unwrap() + u32::try_from(offset).unwrap(),
+                ));
             }
             match lines.next() {
-                Some((_, x)) if x.starts_with("//") => line = x,
-                _ => return false,
+                Some((s, x)) if x.starts_with("//") => (line, line_start) = (x, s),
+                _ => return None,
             }
         }
     }
@@ -377,16 +609,19 @@ fn text_has_safety_comment(src: &str, line_starts: &[BytePos], offset: usize) ->
     let (mut line_start, mut line) = (line_start, line);
     loop {
         if line.starts_with("/*") {
-            let src = src[line_start..line_starts.last().unwrap().to_usize() - offset].trim_start();
+            let src = &src[line_start..line_starts.last().unwrap().to_usize() - offset];
             let mut tokens = tokenize(src);
-            return src[..tokens.next().unwrap().len as usize]
+            return (src[..tokens.next().unwrap().len as usize]
                 .to_ascii_uppercase()
                 .contains("SAFETY:")
-                && tokens.all(|t| t.kind == TokenKind::Whitespace);
+                && tokens.all(|t| t.kind == TokenKind::Whitespace))
+            .then_some(BytePos(
+                u32::try_from(line_start).unwrap() + u32::try_from(offset).unwrap(),
+            ));
         }
         match lines.next() {
             Some(x) => (line_start, line) = x,
-            None => return false,
+            None => return None,
         }
     }
 }
index bc0dd263d88ab2fdf0234097a2c6894609de7630..397633f533b22c767b3e1186d4f172c9341e31c2 100644 (file)
@@ -57,7 +57,7 @@ fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) {
                             format!(
                                 "{}{};",
                                 last_segment.ident,
-                                if let UseTreeKind::Simple(Some(alias), ..) = self_tree.kind { format!(" as {alias}") } else { String::new() },
+                                if let UseTreeKind::Simple(Some(alias)) = self_tree.kind { format!(" as {alias}") } else { String::new() },
                             ),
                             Applicability::MaybeIncorrect,
                         );
index bb6fb38e9690e32a3e472c49f1462bc38fa28d1b..7355260ae4af37bee18b3ea5ee126c3f2538ed21 100644 (file)
@@ -2,14 +2,14 @@
 
 use clippy_utils::ast_utils::{eq_field_pat, eq_id, eq_maybe_qself, eq_pat, eq_path};
 use clippy_utils::diagnostics::span_lint_and_then;
-use clippy_utils::{meets_msrv, msrvs, over};
+use clippy_utils::msrvs::{self, Msrv};
+use clippy_utils::over;
 use rustc_ast::mut_visit::*;
 use rustc_ast::ptr::P;
 use rustc_ast::{self as ast, Mutability, Pat, PatKind, PatKind::*, DUMMY_NODE_ID};
 use rustc_ast_pretty::pprust;
 use rustc_errors::Applicability;
 use rustc_lint::{EarlyContext, EarlyLintPass};
-use rustc_semver::RustcVersion;
 use rustc_session::{declare_tool_lint, impl_lint_pass};
 use rustc_span::DUMMY_SP;
 
     "unnested or-patterns, e.g., `Foo(Bar) | Foo(Baz) instead of `Foo(Bar | Baz)`"
 }
 
-#[derive(Clone, Copy)]
 pub struct UnnestedOrPatterns {
-    msrv: Option<RustcVersion>,
+    msrv: Msrv,
 }
 
 impl UnnestedOrPatterns {
     #[must_use]
-    pub fn new(msrv: Option<RustcVersion>) -> Self {
+    pub fn new(msrv: Msrv) -> Self {
         Self { msrv }
     }
 }
@@ -61,13 +60,13 @@ pub fn new(msrv: Option<RustcVersion>) -> Self {
 
 impl EarlyLintPass for UnnestedOrPatterns {
     fn check_arm(&mut self, cx: &EarlyContext<'_>, a: &ast::Arm) {
-        if meets_msrv(self.msrv, msrvs::OR_PATTERNS) {
+        if self.msrv.meets(msrvs::OR_PATTERNS) {
             lint_unnested_or_patterns(cx, &a.pat);
         }
     }
 
     fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &ast::Expr) {
-        if meets_msrv(self.msrv, msrvs::OR_PATTERNS) {
+        if self.msrv.meets(msrvs::OR_PATTERNS) {
             if let ast::ExprKind::Let(pat, _, _) = &e.kind {
                 lint_unnested_or_patterns(cx, pat);
             }
@@ -75,13 +74,13 @@ fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &ast::Expr) {
     }
 
     fn check_param(&mut self, cx: &EarlyContext<'_>, p: &ast::Param) {
-        if meets_msrv(self.msrv, msrvs::OR_PATTERNS) {
+        if self.msrv.meets(msrvs::OR_PATTERNS) {
             lint_unnested_or_patterns(cx, &p.pat);
         }
     }
 
     fn check_local(&mut self, cx: &EarlyContext<'_>, l: &ast::Local) {
-        if meets_msrv(self.msrv, msrvs::OR_PATTERNS) {
+        if self.msrv.meets(msrvs::OR_PATTERNS) {
             lint_unnested_or_patterns(cx, &l.pat);
         }
     }
index 952586527689af042908087005a2c5974580b1ad..7ee785804f0a564ad9b2a68cc46d75022159aec5 100644 (file)
@@ -39,7 +39,7 @@ fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) {
 
 fn check_use_tree(use_tree: &UseTree, cx: &EarlyContext<'_>, span: Span) {
     match use_tree.kind {
-        UseTreeKind::Simple(Some(new_name), ..) => {
+        UseTreeKind::Simple(Some(new_name)) => {
             let old_name = use_tree
                 .prefix
                 .segments
@@ -48,7 +48,7 @@ fn check_use_tree(use_tree: &UseTree, cx: &EarlyContext<'_>, span: Span) {
                 .ident;
             unsafe_to_safe_check(old_name, new_name, cx, span);
         },
-        UseTreeKind::Simple(None, ..) | UseTreeKind::Glob => {},
+        UseTreeKind::Simple(None) | UseTreeKind::Glob => {},
         UseTreeKind::Nested(ref nested_use_tree) => {
             for (use_tree, _) in nested_use_tree {
                 check_use_tree(use_tree, cx, span);
index aac6719a8dc0feef10b0ea7c4f1578f8732195ca..097568cd1f70037921ee4f5c6b2bc601a8aacee5 100644 (file)
@@ -1,4 +1,5 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::source::snippet;
 use rustc_ast::ast::{Expr, ExprKind, MethodCall};
 use rustc_errors::Applicability;
 use rustc_lint::{EarlyContext, EarlyLintPass};
 }
 declare_lint_pass!(UnusedRounding => [UNUSED_ROUNDING]);
 
-fn is_useless_rounding(expr: &Expr) -> Option<(&str, String)> {
+fn is_useless_rounding<'a>(cx: &EarlyContext<'_>, expr: &'a Expr) -> Option<(&'a str, String)> {
     if let ExprKind::MethodCall(box MethodCall { seg:name_ident, receiver, .. }) = &expr.kind
         && let method_name = name_ident.ident.name.as_str()
         && (method_name == "ceil" || method_name == "round" || method_name == "floor")
         && let ExprKind::Lit(token_lit) = &receiver.kind
-        && token_lit.is_semantic_float() {
-            let mut f_str = token_lit.symbol.to_string();
-            let f = f_str.trim_end_matches('_').parse::<f64>().unwrap();
-            if let Some(suffix) = token_lit.suffix {
-                f_str.push_str(suffix.as_str());
-            }
-            if f.fract() == 0.0 {
-                Some((method_name, f_str))
-            } else {
-                None
-            }
+        && token_lit.is_semantic_float()
+        && let Ok(f) = token_lit.symbol.as_str().replace('_', "").parse::<f64>() {
+            (f.fract() == 0.0).then(||
+                (method_name, snippet(cx, receiver.span, "..").to_string())
+            )
         } else {
             None
         }
@@ -52,7 +47,7 @@ fn is_useless_rounding(expr: &Expr) -> Option<(&str, String)> {
 
 impl EarlyLintPass for UnusedRounding {
     fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) {
-        if let Some((method_name, float)) = is_useless_rounding(expr) {
+        if let Some((method_name, float)) = is_useless_rounding(cx, expr) {
             span_lint_and_sugg(
                 cx,
                 UNUSED_ROUNDING,
index e2860db71a5a772a945f11bced95c435051bf8d7..4c755d812a0e0fe93c319fc6fa534be220d71022 100644 (file)
@@ -1,6 +1,7 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::is_from_proc_macro;
+use clippy_utils::msrvs::{self, Msrv};
 use clippy_utils::ty::same_type_and_consts;
-use clippy_utils::{is_from_proc_macro, meets_msrv, msrvs};
 use if_chain::if_chain;
 use rustc_data_structures::fx::FxHashSet;
 use rustc_errors::Applicability;
@@ -14,7 +15,6 @@
 };
 use rustc_hir_analysis::hir_ty_to_ty;
 use rustc_lint::{LateContext, LateLintPass};
-use rustc_semver::RustcVersion;
 use rustc_session::{declare_tool_lint, impl_lint_pass};
 use rustc_span::Span;
 
 
 #[derive(Default)]
 pub struct UseSelf {
-    msrv: Option<RustcVersion>,
+    msrv: Msrv,
     stack: Vec<StackItem>,
 }
 
 impl UseSelf {
     #[must_use]
-    pub fn new(msrv: Option<RustcVersion>) -> Self {
+    pub fn new(msrv: Msrv) -> Self {
         Self {
             msrv,
             ..Self::default()
@@ -199,7 +199,7 @@ fn check_body_post(&mut self, _: &LateContext<'_>, _: &hir::Body<'_>) {
     fn check_ty(&mut self, cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>) {
         if_chain! {
             if !hir_ty.span.from_expansion();
-            if meets_msrv(self.msrv, msrvs::TYPE_ALIAS_ENUM_VARIANTS);
+            if self.msrv.meets(msrvs::TYPE_ALIAS_ENUM_VARIANTS);
             if let Some(&StackItem::Check {
                 impl_id,
                 in_body,
@@ -228,7 +228,7 @@ fn check_ty(&mut self, cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>) {
     fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
         if_chain! {
             if !expr.span.from_expansion();
-            if meets_msrv(self.msrv, msrvs::TYPE_ALIAS_ENUM_VARIANTS);
+            if self.msrv.meets(msrvs::TYPE_ALIAS_ENUM_VARIANTS);
             if let Some(&StackItem::Check { impl_id, .. }) = self.stack.last();
             if cx.typeck_results().expr_ty(expr) == cx.tcx.type_of(impl_id);
             then {} else { return; }
@@ -248,7 +248,7 @@ fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
     fn check_pat(&mut self, cx: &LateContext<'_>, pat: &Pat<'_>) {
         if_chain! {
             if !pat.span.from_expansion();
-            if meets_msrv(self.msrv, msrvs::TYPE_ALIAS_ENUM_VARIANTS);
+            if self.msrv.meets(msrvs::TYPE_ALIAS_ENUM_VARIANTS);
             if let Some(&StackItem::Check { impl_id, .. }) = self.stack.last();
             // get the path from the pattern
             if let PatKind::Path(QPath::Resolved(_, path))
index b37d4239477eaa1c2ed866cd3112173f71f6f2b7..b6dc8cd7ab1197e338e653a2fa3e1d5f20442877 100644 (file)
@@ -402,6 +402,10 @@ pub(crate) fn get_configuration_metadata() -> Vec<ClippyConfiguration> {
     /// A list of paths to types that should be treated like `Arc`, i.e. ignored but
     /// for the generic parameters for determining interior mutability
     (ignore_interior_mutability: Vec<String> = Vec::from(["bytes::Bytes".into()])),
+    /// Lint: UNINLINED_FORMAT_ARGS.
+    ///
+    /// Whether to allow mixed uninlined format args, e.g. `format!("{} {}", a, foo.bar)`
+    (allow_mixed_uninlined_format_args: bool = true),
 }
 
 /// Search for the configuration file.
index 1aebb8b3104ba611482d1f86c9b4e5f2a0b00fc8..786d9608c851ee1001e1c59c36c1a0911e313544 100644 (file)
@@ -330,7 +330,7 @@ struct LintCollector<'a, 'tcx> {
 impl<'a, 'tcx> Visitor<'tcx> for LintCollector<'a, 'tcx> {
     type NestedFilter = nested_filter::All;
 
-    fn visit_path(&mut self, path: &'tcx Path<'_>, _: HirId) {
+    fn visit_path(&mut self, path: &Path<'_>, _: HirId) {
         if path.segments.len() == 1 {
             self.output.insert(path.segments[0].ident.name);
         }
index d06a616e4b30b2d8ee796e9cc5fe5d967d99f6d3..857abe77e21f239c6225a1dd06b6d45348d38d5b 100644 (file)
@@ -1019,7 +1019,7 @@ fn nested_visit_map(&mut self) -> Self::Map {
         self.cx.tcx.hir()
     }
 
-    fn visit_path(&mut self, path: &'hir hir::Path<'hir>, _id: hir::HirId) {
+    fn visit_path(&mut self, path: &hir::Path<'hir>, _id: hir::HirId) {
         for (index, enum_value) in paths::APPLICABILITY_VALUES.iter().enumerate() {
             if match_path(path, enum_value) {
                 self.add_new_index(index);
index 1e994e3f2b1713b1c2cef1502479177d8f7566e0..9876a8a765ccbca52ed97abc0aa2d89769ad2bab 100644 (file)
@@ -41,7 +41,7 @@ fn check_item(&mut self, cx: &LateContext<'_>, item: &hir::Item<'_>) {
                     .type_of(f.did)
                     .walk()
                     .filter(|t| matches!(t.unpack(), GenericArgKind::Type(_)))
-                    .any(|t| match_type(cx, t.expect_ty(), &paths::RUSTC_VERSION))
+                    .any(|t| match_type(cx, t.expect_ty(), &paths::MSRV))
             });
             if !items.iter().any(|item| item.ident.name == sym!(enter_lint_attrs));
             then {
index be98344470b9c5dbc2a6635b9657c820c201a47d..e4d1ee195c4dfb10aed5eed874f7de6fe280d84d 100644 (file)
@@ -176,7 +176,8 @@ fn check_item(&mut self, cx: &LateContext<'_>, item: &Item<'_>) {
                     format!("{import_source_snippet}::{imports_string}")
                 };
 
-                let (lint, message) = if let Res::Def(DefKind::Enum, _) = use_path.res {
+                // Glob imports always have a single resolution.
+                let (lint, message) = if let Res::Def(DefKind::Enum, _) = use_path.res[0] {
                     (ENUM_GLOB_USE, "usage of wildcard import for enum variants")
                 } else {
                     (WILDCARD_IMPORTS, "usage of wildcard import")
index 6bcf0bbd7eb75f8ef50e8ea81b390d2e610be8cb..49e5f283db08904b5e273449a9f3696343dcab3a 100644 (file)
@@ -566,7 +566,7 @@ pub fn eq_use_tree_kind(l: &UseTreeKind, r: &UseTreeKind) -> bool {
     use UseTreeKind::*;
     match (l, r) {
         (Glob, Glob) => true,
-        (Simple(l, _, _), Simple(r, _, _)) => both(l, r, |l, r| eq_id(*l, *r)),
+        (Simple(l), Simple(r)) => both(l, r, |l, r| eq_id(*l, *r)),
         (Nested(l), Nested(r)) => over(l, r, |(l, _), (r, _)| eq_use_tree(l, r)),
         _ => false,
     }
index cd8575c90e86caaad333ab8f76ecce98d82b3ae8..7987a233bdc184b960f9c53fbd4b9d2c0d0c7619 100644 (file)
@@ -125,19 +125,19 @@ fn parse_attrs<F: FnMut(u64)>(sess: &Session, attrs: &[ast::Attribute], name: &'
     }
 }
 
-pub fn get_unique_inner_attr(sess: &Session, attrs: &[ast::Attribute], name: &'static str) -> Option<ast::Attribute> {
-    let mut unique_attr = None;
+pub fn get_unique_attr<'a>(
+    sess: &'a Session,
+    attrs: &'a [ast::Attribute],
+    name: &'static str,
+) -> Option<&'a ast::Attribute> {
+    let mut unique_attr: Option<&ast::Attribute> = None;
     for attr in get_attr(sess, attrs, name) {
-        match attr.style {
-            ast::AttrStyle::Inner if unique_attr.is_none() => unique_attr = Some(attr.clone()),
-            ast::AttrStyle::Inner => {
-                sess.struct_span_err(attr.span, &format!("`{name}` is defined multiple times"))
-                    .span_note(unique_attr.as_ref().unwrap().span, "first definition found here")
-                    .emit();
-            },
-            ast::AttrStyle::Outer => {
-                sess.span_err(attr.span, format!("`{name}` cannot be an outer attribute"));
-            },
+        if let Some(duplicate) = unique_attr {
+            sess.struct_span_err(attr.span, &format!("`{name}` is defined multiple times"))
+                .span_note(duplicate.span, "first definition found here")
+                .emit();
+        } else {
+            unique_attr = Some(attr);
         }
     }
     unique_attr
index f74f7dadfa90809aedb880e349a98515a98748c9..96711936968b5d4ddd1f3f7fb0f3c52d33a69e9f 100644 (file)
@@ -91,6 +91,16 @@ fn fn_eagerness(cx: &LateContext<'_>, fn_id: DefId, name: Symbol, have_one_arg:
     }
 }
 
+fn res_has_significant_drop(res: Res, cx: &LateContext<'_>, e: &Expr<'_>) -> bool {
+    if let Res::Def(DefKind::Ctor(..) | DefKind::Variant, _) | Res::SelfCtor(_) = res {
+        cx.typeck_results()
+            .expr_ty(e)
+            .has_significant_drop(cx.tcx, cx.param_env)
+    } else {
+        false
+    }
+}
+
 #[expect(clippy::too_many_lines)]
 fn expr_eagerness<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> EagernessSuggestion {
     struct V<'cx, 'tcx> {
@@ -113,13 +123,8 @@ fn visit_expr(&mut self, e: &'tcx Expr<'_>) {
                     },
                     args,
                 ) => match self.cx.qpath_res(path, hir_id) {
-                    Res::Def(DefKind::Ctor(..) | DefKind::Variant, _) | Res::SelfCtor(_) => {
-                        if self
-                            .cx
-                            .typeck_results()
-                            .expr_ty(e)
-                            .has_significant_drop(self.cx.tcx, self.cx.param_env)
-                        {
+                    res @ (Res::Def(DefKind::Ctor(..) | DefKind::Variant, _) | Res::SelfCtor(_)) => {
+                        if res_has_significant_drop(res, self.cx, e) {
                             self.eagerness = ForceNoChange;
                             return;
                         }
@@ -147,6 +152,12 @@ fn visit_expr(&mut self, e: &'tcx Expr<'_>) {
                     self.eagerness |= NoChange;
                     return;
                 },
+                ExprKind::Path(ref path) => {
+                    if res_has_significant_drop(self.cx.qpath_res(path, e.hir_id), self.cx, e) {
+                        self.eagerness = ForceNoChange;
+                        return;
+                    }
+                },
                 ExprKind::MethodCall(name, ..) => {
                     self.eagerness |= self
                         .cx
@@ -206,7 +217,6 @@ fn visit_expr(&mut self, e: &'tcx Expr<'_>) {
                 | ExprKind::Match(..)
                 | ExprKind::Closure { .. }
                 | ExprKind::Field(..)
-                | ExprKind::Path(_)
                 | ExprKind::AddrOf(..)
                 | ExprKind::Struct(..)
                 | ExprKind::Repeat(..)
index 9e2682925a22116c71acdb6847f1572207f84d74..90192f46cbfa09f416e88c94060d3962f5c9cfef 100644 (file)
     layout::IntegerExt, BorrowKind, ClosureKind, DefIdTree, Ty, TyCtxt, TypeAndMut, TypeVisitable, UpvarCapture,
 };
 use rustc_middle::ty::{FloatTy, IntTy, UintTy};
-use rustc_semver::RustcVersion;
-use rustc_session::Session;
 use rustc_span::hygiene::{ExpnKind, MacroKind};
 use rustc_span::source_map::SourceMap;
 use rustc_span::sym;
 use crate::ty::{can_partially_move_ty, expr_sig, is_copy, is_recursively_primitive_type, ty_is_fn_once_param};
 use crate::visitors::for_each_expr;
 
-pub fn parse_msrv(msrv: &str, sess: Option<&Session>, span: Option<Span>) -> Option<RustcVersion> {
-    if let Ok(version) = RustcVersion::parse(msrv) {
-        return Some(version);
-    } else if let Some(sess) = sess {
-        if let Some(span) = span {
-            sess.span_err(span, format!("`{msrv}` is not a valid Rust version"));
-        }
-    }
-    None
-}
-
-pub fn meets_msrv(msrv: Option<RustcVersion>, lint_msrv: RustcVersion) -> bool {
-    msrv.map_or(true, |msrv| msrv.meets(lint_msrv))
-}
-
 #[macro_export]
 macro_rules! extract_msrv_attr {
     ($context:ident) => {
         fn enter_lint_attrs(&mut self, cx: &rustc_lint::$context<'_>, attrs: &[rustc_ast::ast::Attribute]) {
             let sess = rustc_lint::LintContext::sess(cx);
-            match $crate::get_unique_inner_attr(sess, attrs, "msrv") {
-                Some(msrv_attr) => {
-                    if let Some(msrv) = msrv_attr.value_str() {
-                        self.msrv = $crate::parse_msrv(&msrv.to_string(), Some(sess), Some(msrv_attr.span));
-                    } else {
-                        sess.span_err(msrv_attr.span, "bad clippy attribute");
-                    }
-                },
-                _ => (),
-            }
+            self.msrv.enter_lint_attrs(sess, attrs);
+        }
+
+        fn exit_lint_attrs(&mut self, cx: &rustc_lint::$context<'_>, attrs: &[rustc_ast::ast::Attribute]) {
+            let sess = rustc_lint::LintContext::sess(cx);
+            self.msrv.exit_lint_attrs(sess, attrs);
         }
     };
 }
index 79b19e6fb3eb051eff7a865ac44ea944e4d9cd88..12a512f78a699eb30c92ac178b17663db424d090 100644 (file)
@@ -1,4 +1,11 @@
+use std::sync::OnceLock;
+
+use rustc_ast::Attribute;
 use rustc_semver::RustcVersion;
+use rustc_session::Session;
+use rustc_span::Span;
+
+use crate::attrs::get_unique_attr;
 
 macro_rules! msrv_aliases {
     ($($major:literal,$minor:literal,$patch:literal {
@@ -40,3 +47,97 @@ macro_rules! msrv_aliases {
     1,16,0 { STR_REPEAT }
     1,55,0 { SEEK_REWIND }
 }
+
+fn parse_msrv(msrv: &str, sess: Option<&Session>, span: Option<Span>) -> Option<RustcVersion> {
+    if let Ok(version) = RustcVersion::parse(msrv) {
+        return Some(version);
+    } else if let Some(sess) = sess {
+        if let Some(span) = span {
+            sess.span_err(span, format!("`{msrv}` is not a valid Rust version"));
+        }
+    }
+    None
+}
+
+/// Tracks the current MSRV from `clippy.toml`, `Cargo.toml` or set via `#[clippy::msrv]`
+#[derive(Debug, Clone, Default)]
+pub struct Msrv {
+    stack: Vec<RustcVersion>,
+}
+
+impl Msrv {
+    fn new(initial: Option<RustcVersion>) -> Self {
+        Self {
+            stack: Vec::from_iter(initial),
+        }
+    }
+
+    fn read_inner(conf_msrv: &Option<String>, sess: &Session) -> Self {
+        let cargo_msrv = std::env::var("CARGO_PKG_RUST_VERSION")
+            .ok()
+            .and_then(|v| parse_msrv(&v, None, None));
+        let clippy_msrv = conf_msrv.as_ref().and_then(|s| {
+            parse_msrv(s, None, None).or_else(|| {
+                sess.err(format!(
+                    "error reading Clippy's configuration file. `{s}` is not a valid Rust version"
+                ));
+                None
+            })
+        });
+
+        // if both files have an msrv, let's compare them and emit a warning if they differ
+        if let Some(cargo_msrv) = cargo_msrv
+            && let Some(clippy_msrv) = clippy_msrv
+            && clippy_msrv != cargo_msrv
+        {
+            sess.warn(format!(
+                "the MSRV in `clippy.toml` and `Cargo.toml` differ; using `{clippy_msrv}` from `clippy.toml`"
+            ));
+        }
+
+        Self::new(clippy_msrv.or(cargo_msrv))
+    }
+
+    /// Set the initial MSRV from the Clippy config file or from Cargo due to the `rust-version`
+    /// field in `Cargo.toml`
+    ///
+    /// Returns a `&'static Msrv` as `Copy` types are more easily passed to the
+    /// `register_{late,early}_pass` callbacks
+    pub fn read(conf_msrv: &Option<String>, sess: &Session) -> &'static Self {
+        static PARSED: OnceLock<Msrv> = OnceLock::new();
+
+        PARSED.get_or_init(|| Self::read_inner(conf_msrv, sess))
+    }
+
+    pub fn current(&self) -> Option<RustcVersion> {
+        self.stack.last().copied()
+    }
+
+    pub fn meets(&self, required: RustcVersion) -> bool {
+        self.current().map_or(true, |version| version.meets(required))
+    }
+
+    fn parse_attr(sess: &Session, attrs: &[Attribute]) -> Option<RustcVersion> {
+        if let Some(msrv_attr) = get_unique_attr(sess, attrs, "msrv") {
+            if let Some(msrv) = msrv_attr.value_str() {
+                return parse_msrv(&msrv.to_string(), Some(sess), Some(msrv_attr.span));
+            }
+
+            sess.span_err(msrv_attr.span, "bad clippy attribute");
+        }
+
+        None
+    }
+
+    pub fn enter_lint_attrs(&mut self, sess: &Session, attrs: &[Attribute]) {
+        if let Some(version) = Self::parse_attr(sess, attrs) {
+            self.stack.push(version);
+        }
+    }
+
+    pub fn exit_lint_attrs(&mut self, sess: &Session, attrs: &[Attribute]) {
+        if Self::parse_attr(sess, attrs).is_some() {
+            self.stack.pop();
+        }
+    }
+}
index 6c09c146082ab41e673ea06b142afb334fea833c..6417f0f3c71348bb6761918cb08c7c373e7b9bc6 100644 (file)
@@ -60,6 +60,8 @@
 #[cfg(feature = "internal")]
 pub const LINT: [&str; 2] = ["rustc_lint_defs", "Lint"];
 pub const MEM_SWAP: [&str; 3] = ["core", "mem", "swap"];
+#[cfg(feature = "internal")]
+pub const MSRV: [&str; 3] = ["clippy_utils", "msrvs", "Msrv"];
 pub const OPEN_OPTIONS: [&str; 3] = ["std", "fs", "OpenOptions"];
 pub const OS_STRING_AS_OS_STR: [&str; 5] = ["std", "ffi", "os_str", "OsString", "as_os_str"];
 pub const OS_STR_TO_OS_STRING: [&str; 5] = ["std", "ffi", "os_str", "OsStr", "to_os_string"];
@@ -72,7 +74,6 @@
 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"];
-pub const POLL: [&str; 4] = ["core", "task", "poll", "Poll"];
 pub const PTR_COPY: [&str; 3] = ["core", "intrinsics", "copy"];
 pub const PTR_COPY_NONOVERLAPPING: [&str; 3] = ["core", "intrinsics", "copy_nonoverlapping"];
 pub const PTR_EQ: [&str; 3] = ["core", "ptr", "eq"];
 pub const REGEX_BYTES_SET_NEW: [&str; 5] = ["regex", "re_set", "bytes", "RegexSet", "new"];
 pub const REGEX_NEW: [&str; 4] = ["regex", "re_unicode", "Regex", "new"];
 pub const REGEX_SET_NEW: [&str; 5] = ["regex", "re_set", "unicode", "RegexSet", "new"];
-#[cfg(feature = "internal")]
-pub const RUSTC_VERSION: [&str; 2] = ["rustc_semver", "RustcVersion"];
 pub const SERDE_DESERIALIZE: [&str; 3] = ["serde", "de", "Deserialize"];
 pub const SERDE_DE_VISITOR: [&str; 3] = ["serde", "de", "Visitor"];
 pub const SLICE_FROM_RAW_PARTS: [&str; 4] = ["core", "slice", "raw", "from_raw_parts"];
index b8c2dd5ab9ea16ee31ac7111304444bd16484774..e053a9dc8881ab2a0cd2adf7eb52bf71436b8d37 100644 (file)
@@ -3,6 +3,7 @@
 // of terminologies might not be relevant in the context of Clippy. Note that its behavior might
 // differ from the time of `rustc` even if the name stays the same.
 
+use crate::msrvs::Msrv;
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
 use rustc_middle::mir::{
 
 type McfResult = Result<(), (Span, Cow<'static, str>)>;
 
-pub fn is_min_const_fn<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>, msrv: Option<RustcVersion>) -> McfResult {
+pub fn is_min_const_fn<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>, msrv: &Msrv) -> McfResult {
     let def_id = body.source.def_id();
     let mut current = def_id;
     loop {
         let predicates = tcx.predicates_of(current);
         for (predicate, _) in predicates.predicates {
             match predicate.kind().skip_binder() {
-                ty::PredicateKind::Clause(ty::Clause::RegionOutlives(_))
-                | ty::PredicateKind::Clause(ty::Clause::TypeOutlives(_))
+                ty::PredicateKind::Clause(
+                    ty::Clause::RegionOutlives(_)
+                    | ty::Clause::TypeOutlives(_)
+                    | ty::Clause::Projection(_)
+                    | ty::Clause::Trait(..),
+                )
                 | ty::PredicateKind::WellFormed(_)
-                | ty::PredicateKind::Clause(ty::Clause::Projection(_))
                 | ty::PredicateKind::ConstEvaluatable(..)
                 | ty::PredicateKind::ConstEquate(..)
-                | ty::PredicateKind::Clause(ty::Clause::Trait(..))
                 | ty::PredicateKind::TypeWellFormedFromEnv(..) => continue,
                 ty::PredicateKind::ObjectSafe(_) => panic!("object safe predicate on function: {predicate:#?}"),
                 ty::PredicateKind::ClosureKind(..) => panic!("closure kind predicate on function: {predicate:#?}"),
@@ -281,7 +284,7 @@ fn check_terminator<'tcx>(
     tcx: TyCtxt<'tcx>,
     body: &Body<'tcx>,
     terminator: &Terminator<'tcx>,
-    msrv: Option<RustcVersion>,
+    msrv: &Msrv,
 ) -> McfResult {
     let span = terminator.source_info.span;
     match &terminator.kind {
@@ -300,7 +303,6 @@ fn check_terminator<'tcx>(
 
         TerminatorKind::SwitchInt {
             discr,
-            switch_ty: _,
             targets: _,
         } => check_operand(tcx, discr, span, body),
 
@@ -365,7 +367,7 @@ fn check_terminator<'tcx>(
     }
 }
 
-fn is_const_fn(tcx: TyCtxt<'_>, def_id: DefId, msrv: Option<RustcVersion>) -> bool {
+fn is_const_fn(tcx: TyCtxt<'_>, def_id: DefId, msrv: &Msrv) -> bool {
     tcx.is_const_fn(def_id)
         && tcx.lookup_const_stability(def_id).map_or(true, |const_stab| {
             if let rustc_attr::StabilityLevel::Stable { since, .. } = const_stab.level {
@@ -384,15 +386,12 @@ fn is_const_fn(tcx: TyCtxt<'_>, def_id: DefId, msrv: Option<RustcVersion>) -> bo
 
                 let since = rustc_span::Symbol::intern(short_version);
 
-                crate::meets_msrv(
-                    msrv,
-                    RustcVersion::parse(since.as_str()).unwrap_or_else(|err| {
-                        panic!("`rustc_attr::StabilityLevel::Stable::since` is ill-formatted: `{since}`, {err:?}")
-                    }),
-                )
+                msrv.meets(RustcVersion::parse(since.as_str()).unwrap_or_else(|err| {
+                    panic!("`rustc_attr::StabilityLevel::Stable::since` is ill-formatted: `{since}`, {err:?}")
+                }))
             } else {
                 // Unstable const fn with the feature enabled.
-                msrv.is_none()
+                msrv.current().is_none()
             }
         })
 }
index eacfa91ba556d41d454f2b3a63c5a325ae4311cd..cd5dcfdaca34b64245632331bd7707c36205adcd 100644 (file)
@@ -5,6 +5,7 @@
 use rustc_errors::Applicability;
 use rustc_hir::{Expr, ExprKind};
 use rustc_lint::{LateContext, LintContext};
+use rustc_session::Session;
 use rustc_span::hygiene;
 use rustc_span::source_map::{original_sp, SourceMap};
 use rustc_span::{BytePos, Pos, Span, SpanData, SyntaxContext, DUMMY_SP};
@@ -204,11 +205,20 @@ pub fn snippet_with_applicability<'a, T: LintContext>(
     span: Span,
     default: &'a str,
     applicability: &mut Applicability,
+) -> Cow<'a, str> {
+    snippet_with_applicability_sess(cx.sess(), span, default, applicability)
+}
+
+fn snippet_with_applicability_sess<'a>(
+    sess: &Session,
+    span: Span,
+    default: &'a str,
+    applicability: &mut Applicability,
 ) -> Cow<'a, str> {
     if *applicability != Applicability::Unspecified && span.from_expansion() {
         *applicability = Applicability::MaybeIncorrect;
     }
-    snippet_opt(cx, span).map_or_else(
+    snippet_opt_sess(sess, span).map_or_else(
         || {
             if *applicability == Applicability::MachineApplicable {
                 *applicability = Applicability::HasPlaceholders;
@@ -226,8 +236,12 @@ pub fn snippet_with_macro_callsite<'a, T: LintContext>(cx: &T, span: Span, defau
 }
 
 /// Converts a span to a code snippet. Returns `None` if not available.
-pub fn snippet_opt<T: LintContext>(cx: &T, span: Span) -> Option<String> {
-    cx.sess().source_map().span_to_snippet(span).ok()
+pub fn snippet_opt(cx: &impl LintContext, span: Span) -> Option<String> {
+    snippet_opt_sess(cx.sess(), span)
+}
+
+fn snippet_opt_sess(sess: &Session, span: Span) -> Option<String> {
+    sess.source_map().span_to_snippet(span).ok()
 }
 
 /// Converts a span (from a block) to a code snippet if available, otherwise use default.
@@ -277,8 +291,8 @@ pub fn snippet_block<'a, T: LintContext>(
 
 /// Same as `snippet_block`, but adapts the applicability level by the rules of
 /// `snippet_with_applicability`.
-pub fn snippet_block_with_applicability<'a, T: LintContext>(
-    cx: &T,
+pub fn snippet_block_with_applicability<'a>(
+    cx: &impl LintContext,
     span: Span,
     default: &'a str,
     indent_relative_to: Option<Span>,
@@ -299,7 +313,17 @@ pub fn snippet_block_with_applicability<'a, T: LintContext>(
 ///
 /// This will also return whether or not the snippet is a macro call.
 pub fn snippet_with_context<'a>(
-    cx: &LateContext<'_>,
+    cx: &impl LintContext,
+    span: Span,
+    outer: SyntaxContext,
+    default: &'a str,
+    applicability: &mut Applicability,
+) -> (Cow<'a, str>, bool) {
+    snippet_with_context_sess(cx.sess(), span, outer, default, applicability)
+}
+
+fn snippet_with_context_sess<'a>(
+    sess: &Session,
     span: Span,
     outer: SyntaxContext,
     default: &'a str,
@@ -318,7 +342,7 @@ pub fn snippet_with_context<'a>(
     );
 
     (
-        snippet_with_applicability(cx, span, default, applicability),
+        snippet_with_applicability_sess(sess, span, default, applicability),
         is_macro_call,
     )
 }
index 3cacdb493772138594a03114722fc2b10c9c74ff..b66604f33db1799d49b8fd5fb9b3ccfaa40fa1f1 100644 (file)
@@ -176,25 +176,28 @@ fn hir_from_snippet(expr: &hir::Expr<'_>, get_snippet: impl Fn(Span) -> Cow<'a,
     }
 
     /// Prepare a suggestion from an expression.
-    pub fn ast(cx: &EarlyContext<'_>, expr: &ast::Expr, default: &'a str) -> Self {
+    pub fn ast(
+        cx: &EarlyContext<'_>,
+        expr: &ast::Expr,
+        default: &'a str,
+        ctxt: SyntaxContext,
+        app: &mut Applicability,
+    ) -> Self {
         use rustc_ast::ast::RangeLimits;
 
-        let snippet_without_expansion = |cx, span: Span, default| {
-            if span.from_expansion() {
-                snippet_with_macro_callsite(cx, span, default)
-            } else {
-                snippet(cx, span, default)
-            }
-        };
-
+        #[expect(clippy::match_wildcard_for_single_variants)]
         match expr.kind {
+            _ if expr.span.ctxt() != ctxt => Sugg::NonParen(snippet_with_context(cx, expr.span, ctxt, default, app).0),
             ast::ExprKind::AddrOf(..)
             | ast::ExprKind::Box(..)
             | ast::ExprKind::Closure { .. }
             | ast::ExprKind::If(..)
             | ast::ExprKind::Let(..)
             | ast::ExprKind::Unary(..)
-            | ast::ExprKind::Match(..) => Sugg::MaybeParen(snippet_without_expansion(cx, expr.span, default)),
+            | ast::ExprKind::Match(..) => match snippet_with_context(cx, expr.span, ctxt, default, app) {
+                (snip, false) => Sugg::MaybeParen(snip),
+                (snip, true) => Sugg::NonParen(snip),
+            },
             ast::ExprKind::Async(..)
             | ast::ExprKind::Block(..)
             | ast::ExprKind::Break(..)
@@ -224,45 +227,49 @@ pub fn ast(cx: &EarlyContext<'_>, expr: &ast::Expr, default: &'a str) -> Self {
             | ast::ExprKind::Array(..)
             | ast::ExprKind::While(..)
             | ast::ExprKind::Await(..)
-            | ast::ExprKind::Err => Sugg::NonParen(snippet_without_expansion(cx, expr.span, default)),
+            | ast::ExprKind::Err => Sugg::NonParen(snippet_with_context(cx, expr.span, ctxt, default, app).0),
             ast::ExprKind::Range(ref lhs, ref rhs, RangeLimits::HalfOpen) => Sugg::BinOp(
                 AssocOp::DotDot,
-                lhs.as_ref()
-                    .map_or("".into(), |lhs| snippet_without_expansion(cx, lhs.span, default)),
-                rhs.as_ref()
-                    .map_or("".into(), |rhs| snippet_without_expansion(cx, rhs.span, default)),
+                lhs.as_ref().map_or("".into(), |lhs| {
+                    snippet_with_context(cx, lhs.span, ctxt, default, app).0
+                }),
+                rhs.as_ref().map_or("".into(), |rhs| {
+                    snippet_with_context(cx, rhs.span, ctxt, default, app).0
+                }),
             ),
             ast::ExprKind::Range(ref lhs, ref rhs, RangeLimits::Closed) => Sugg::BinOp(
                 AssocOp::DotDotEq,
-                lhs.as_ref()
-                    .map_or("".into(), |lhs| snippet_without_expansion(cx, lhs.span, default)),
-                rhs.as_ref()
-                    .map_or("".into(), |rhs| snippet_without_expansion(cx, rhs.span, default)),
+                lhs.as_ref().map_or("".into(), |lhs| {
+                    snippet_with_context(cx, lhs.span, ctxt, default, app).0
+                }),
+                rhs.as_ref().map_or("".into(), |rhs| {
+                    snippet_with_context(cx, rhs.span, ctxt, default, app).0
+                }),
             ),
             ast::ExprKind::Assign(ref lhs, ref rhs, _) => Sugg::BinOp(
                 AssocOp::Assign,
-                snippet_without_expansion(cx, lhs.span, default),
-                snippet_without_expansion(cx, rhs.span, default),
+                snippet_with_context(cx, lhs.span, ctxt, default, app).0,
+                snippet_with_context(cx, rhs.span, ctxt, default, app).0,
             ),
             ast::ExprKind::AssignOp(op, ref lhs, ref rhs) => Sugg::BinOp(
                 astbinop2assignop(op),
-                snippet_without_expansion(cx, lhs.span, default),
-                snippet_without_expansion(cx, rhs.span, default),
+                snippet_with_context(cx, lhs.span, ctxt, default, app).0,
+                snippet_with_context(cx, rhs.span, ctxt, default, app).0,
             ),
             ast::ExprKind::Binary(op, ref lhs, ref rhs) => Sugg::BinOp(
                 AssocOp::from_ast_binop(op.node),
-                snippet_without_expansion(cx, lhs.span, default),
-                snippet_without_expansion(cx, rhs.span, default),
+                snippet_with_context(cx, lhs.span, ctxt, default, app).0,
+                snippet_with_context(cx, rhs.span, ctxt, default, app).0,
             ),
             ast::ExprKind::Cast(ref lhs, ref ty) => Sugg::BinOp(
                 AssocOp::As,
-                snippet_without_expansion(cx, lhs.span, default),
-                snippet_without_expansion(cx, ty.span, default),
+                snippet_with_context(cx, lhs.span, ctxt, default, app).0,
+                snippet_with_context(cx, ty.span, ctxt, default, app).0,
             ),
             ast::ExprKind::Type(ref lhs, ref ty) => Sugg::BinOp(
                 AssocOp::Colon,
-                snippet_without_expansion(cx, lhs.span, default),
-                snippet_without_expansion(cx, ty.span, default),
+                snippet_with_context(cx, lhs.span, ctxt, default, app).0,
+                snippet_with_context(cx, ty.span, ctxt, default, app).0,
             ),
         }
     }
index 2ceda3511fe44642b1a822dcddd5eb8857e8da2b..bfb2d472a393cf0525955de8f38dce24e0f270b2 100644 (file)
@@ -9,7 +9,10 @@
 use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res};
 use rustc_hir::def_id::DefId;
 use rustc_hir::{Expr, FnDecl, LangItem, TyKind, Unsafety};
-use rustc_infer::infer::{TyCtxtInferExt, type_variable::{TypeVariableOrigin, TypeVariableOriginKind}};
+use rustc_infer::infer::{
+    type_variable::{TypeVariableOrigin, TypeVariableOriginKind},
+    TyCtxtInferExt,
+};
 use rustc_lint::LateContext;
 use rustc_middle::mir::interpret::{ConstValue, Scalar};
 use rustc_middle::ty::{
@@ -189,7 +192,13 @@ pub fn implements_trait<'tcx>(
     trait_id: DefId,
     ty_params: &[GenericArg<'tcx>],
 ) -> bool {
-    implements_trait_with_env(cx.tcx, cx.param_env, ty, trait_id, ty_params.iter().map(|&arg| Some(arg)))
+    implements_trait_with_env(
+        cx.tcx,
+        cx.param_env,
+        ty,
+        trait_id,
+        ty_params.iter().map(|&arg| Some(arg)),
+    )
 }
 
 /// Same as `implements_trait` but allows using a `ParamEnv` different from the lint context.
@@ -212,7 +221,11 @@ pub fn implements_trait_with_env<'tcx>(
         kind: TypeVariableOriginKind::MiscVariable,
         span: DUMMY_SP,
     };
-    let ty_params = tcx.mk_substs(ty_params.into_iter().map(|arg| arg.unwrap_or_else(|| infcx.next_ty_var(orig).into())));
+    let ty_params = tcx.mk_substs(
+        ty_params
+            .into_iter()
+            .map(|arg| arg.unwrap_or_else(|| infcx.next_ty_var(orig).into())),
+    );
     infcx
         .type_implements_trait(trait_id, [ty.into()].into_iter().chain(ty_params), param_env)
         .must_apply_modulo_regions()
@@ -712,7 +725,9 @@ fn sig_for_projection<'tcx>(cx: &LateContext<'tcx>, ty: ProjectionTy<'tcx>) -> O
                 }
                 inputs = Some(i);
             },
-            PredicateKind::Clause(ty::Clause::Projection(p)) if Some(p.projection_ty.item_def_id) == lang_items.fn_once_output() => {
+            PredicateKind::Clause(ty::Clause::Projection(p))
+                if Some(p.projection_ty.item_def_id) == lang_items.fn_once_output() =>
+            {
                 if output.is_some() {
                     // Multiple different fn trait impls. Is this even allowed?
                     return None;
@@ -992,14 +1007,12 @@ fn helper<'tcx>(
 
             debug_assert!(
                 generic_count == substs.len(),
-                "wrong number of substs for `{:?}`: found `{}` expected `{}`.\n\
+                "wrong number of substs for `{:?}`: found `{}` expected `{generic_count}`.\n\
                     note: the expected parameters are: {:#?}\n\
-                    the given arguments are: `{:#?}`",
+                    the given arguments are: `{substs:#?}`",
                 assoc_item.def_id,
                 substs.len(),
-                generic_count,
                 params.map(ty::GenericParamDefKind::descr).collect::<Vec<_>>(),
-                substs,
             );
 
             if let Some((idx, (param, arg))) = params
@@ -1017,14 +1030,11 @@ fn helper<'tcx>(
             {
                 debug_assert!(
                     false,
-                    "mismatched subst type at index {}: expected a {}, found `{:?}`\n\
+                    "mismatched subst type at index {idx}: expected a {}, found `{arg:?}`\n\
                         note: the expected parameters are {:#?}\n\
-                        the given arguments are {:#?}",
-                    idx,
+                        the given arguments are {substs:#?}",
                     param.descr(),
-                    arg,
-                    params.map(ty::GenericParamDefKind::descr).collect::<Vec<_>>(),
-                    substs,
+                    params.map(ty::GenericParamDefKind::descr).collect::<Vec<_>>()
                 );
             }
         }
index 797722cfc1fcc5c0a60b74cf9178037c4a0ed686..ab3976a13bdbbf4f8524e965e209f62165f623ce 100644 (file)
@@ -128,7 +128,7 @@ fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) {
         }
     }
 
-    fn visit_path(&mut self, path: &'tcx hir::Path<'tcx>, _: hir::HirId) {
+    fn visit_path(&mut self, path: &hir::Path<'tcx>, _: hir::HirId) {
         if let hir::def::Res::Local(id) = path.res {
             if self.binding_ids.contains(&id) {
                 self.usage_found = true;
index d4294f18fd5019c0eed128e9321f8caca80b0109..863fb60fcfca1fb09aee2de418dcd9c0743d7855 100644 (file)
@@ -170,22 +170,22 @@ struct RetFinder<F> {
         cb: F,
     }
 
-    struct WithStmtGuarg<'a, F> {
+    struct WithStmtGuard<'a, F> {
         val: &'a mut RetFinder<F>,
         prev_in_stmt: bool,
     }
 
     impl<F> RetFinder<F> {
-        fn inside_stmt(&mut self, in_stmt: bool) -> WithStmtGuarg<'_, F> {
+        fn inside_stmt(&mut self, in_stmt: bool) -> WithStmtGuard<'_, F> {
             let prev_in_stmt = std::mem::replace(&mut self.in_stmt, in_stmt);
-            WithStmtGuarg {
+            WithStmtGuard {
                 val: self,
                 prev_in_stmt,
             }
         }
     }
 
-    impl<F> std::ops::Deref for WithStmtGuarg<'_, F> {
+    impl<F> std::ops::Deref for WithStmtGuard<'_, F> {
         type Target = RetFinder<F>;
 
         fn deref(&self) -> &Self::Target {
@@ -193,13 +193,13 @@ fn deref(&self) -> &Self::Target {
         }
     }
 
-    impl<F> std::ops::DerefMut for WithStmtGuarg<'_, F> {
+    impl<F> std::ops::DerefMut for WithStmtGuard<'_, F> {
         fn deref_mut(&mut self) -> &mut Self::Target {
             self.val
         }
     }
 
-    impl<F> Drop for WithStmtGuarg<'_, F> {
+    impl<F> Drop for WithStmtGuard<'_, F> {
         fn drop(&mut self) {
             self.val.in_stmt = self.prev_in_stmt;
         }
index ee8ab7c1d7cbbc60395caddeb15bc8d3dcf24d58..bd49f096072630309ef3b38ab333429135ef5e6f 100644 (file)
@@ -120,8 +120,8 @@ fn new(diag: Diagnostic, crate_name: &str, crate_version: &str) -> Option<Self>
             format!("$CARGO_HOME/{}", stripped.display())
         } else {
             format!(
-                "target/lintcheck/sources/{}-{}/{}",
-                crate_name, crate_version, span.file_name
+                "target/lintcheck/sources/{crate_name}-{crate_version}/{}",
+                span.file_name
             )
         };
 
@@ -322,13 +322,13 @@ fn run_clippy_lints(
 
         if config.max_jobs == 1 {
             println!(
-                "{}/{} {}% Linting {} {}",
-                index, total_crates_to_lint, perc, &self.name, &self.version
+                "{index}/{total_crates_to_lint} {perc}% Linting {} {}",
+                &self.name, &self.version
             );
         } else {
             println!(
-                "{}/{} {}% Linting {} {} in target dir {:?}",
-                index, total_crates_to_lint, perc, &self.name, &self.version, thread_index
+                "{index}/{total_crates_to_lint} {perc}% Linting {} {} in target dir {thread_index:?}",
+                &self.name, &self.version
             );
         }
 
@@ -398,8 +398,7 @@ fn run_clippy_lints(
             .output()
             .unwrap_or_else(|error| {
                 panic!(
-                    "Encountered error:\n{:?}\ncargo_clippy_path: {}\ncrate path:{}\n",
-                    error,
+                    "Encountered error:\n{error:?}\ncargo_clippy_path: {}\ncrate path:{}\n",
                     &cargo_clippy_path.display(),
                     &self.path.display()
                 );
index a806c1564796ae2a5bb3b5fd5b0fde0659e17d9e..19fee38db46e642eb18f600b1a3b7d8b6e8a814f 100644 (file)
@@ -1,3 +1,3 @@
 [toolchain]
-channel = "nightly-2022-11-21"
+channel = "nightly-2022-12-01"
 components = ["cargo", "llvm-tools", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"]
index ad6132a49baaec685db1d7b62033b7c820b950d3..9ec4df8e651b1bf3f7756656f8548f5c2ec8e9c0 100644 (file)
@@ -1,6 +1,7 @@
 #![feature(rustc_private)]
 #![feature(let_chains)]
 #![feature(once_cell)]
+#![feature(lint_reasons)]
 #![cfg_attr(feature = "deny-warnings", deny(warnings))]
 // warn on lints, that are included in `rust-lang/rust`s bootstrap
 #![warn(rust_2018_idioms, unused_lifetimes)]
@@ -90,6 +91,10 @@ fn track_files(parse_sess: &mut ParseSess, conf_path_string: Option<String>) {
 
     // During development track the `clippy-driver` executable so that cargo will re-run clippy whenever
     // it is rebuilt
+    #[expect(
+        clippy::collapsible_if,
+        reason = "Due to a bug in let_chains this if statement can't be collapsed"
+    )]
     if cfg!(debug_assertions) {
         if let Ok(current_exe) = env::current_exe()
             && let Some(current_exe) = current_exe.to_str()
index 900a8fffd4080cc9a6894c502b2b968ef0f1ff5a..08634063a5754a775c385ff4ce4e03b48f9a556f 100644 (file)
@@ -11,9 +11,9 @@ extern crate rustc_middle;
 #[macro_use]
 extern crate rustc_session;
 use clippy_utils::extract_msrv_attr;
+use clippy_utils::msrvs::Msrv;
 use rustc_hir::Expr;
 use rustc_lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass};
-use rustc_semver::RustcVersion;
 
 declare_lint! {
     pub TEST_LINT,
@@ -22,7 +22,7 @@ declare_lint! {
 }
 
 struct Pass {
-    msrv: Option<RustcVersion>,
+    msrv: Msrv,
 }
 
 impl_lint_pass!(Pass => [TEST_LINT]);
index 4bc8164db67b016513dfcba17210d10403894382..f8af77e6d395c05201895d362eedb232a7f08108 100644 (file)
@@ -11,9 +11,9 @@
 #[macro_use]
 extern crate rustc_session;
 use clippy_utils::extract_msrv_attr;
+use clippy_utils::msrvs::Msrv;
 use rustc_hir::Expr;
 use rustc_lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass};
-use rustc_semver::RustcVersion;
 
 declare_lint! {
     pub TEST_LINT,
@@ -22,7 +22,7 @@
 }
 
 struct Pass {
-    msrv: Option<RustcVersion>,
+    msrv: Msrv,
 }
 
 impl_lint_pass!(Pass => [TEST_LINT]);
index 8bfc060e991064d98905105f93fa9a398a709351..2a240cc249b0c768f084dab5b6f220ae53a59399 100644 (file)
@@ -1,12 +1,3 @@
-error: hardcoded path to a language item
-  --> $DIR/unnecessary_def_path_hardcoded_path.rs:11:40
-   |
-LL |     const DEREF_MUT_TRAIT: [&str; 4] = ["core", "ops", "deref", "DerefMut"];
-   |                                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = help: convert all references to use `LangItem::DerefMut`
-   = note: `-D clippy::unnecessary-def-path` implied by `-D warnings`
-
 error: hardcoded path to a diagnostic item
   --> $DIR/unnecessary_def_path_hardcoded_path.rs:10:36
    |
@@ -14,6 +5,7 @@ LL |     const DEREF_TRAIT: [&str; 4] = ["core", "ops", "deref", "Deref"];
    |                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: convert all references to use `sym::Deref`
+   = note: `-D clippy::unnecessary-def-path` implied by `-D warnings`
 
 error: hardcoded path to a diagnostic item
   --> $DIR/unnecessary_def_path_hardcoded_path.rs:12:43
@@ -23,5 +15,13 @@ LL |     const DEREF_TRAIT_METHOD: [&str; 5] = ["core", "ops", "deref", "Deref",
    |
    = help: convert all references to use `sym::deref_method`
 
+error: hardcoded path to a language item
+  --> $DIR/unnecessary_def_path_hardcoded_path.rs:11:40
+   |
+LL |     const DEREF_MUT_TRAIT: [&str; 4] = ["core", "ops", "deref", "DerefMut"];
+   |                                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: convert all references to use `LangItem::DerefMut`
+
 error: aborting due to 3 previous errors
 
diff --git a/src/tools/clippy/tests/ui-toml/allow_mixed_uninlined_format_args/clippy.toml b/src/tools/clippy/tests/ui-toml/allow_mixed_uninlined_format_args/clippy.toml
new file mode 100644 (file)
index 0000000..b95e806
--- /dev/null
@@ -0,0 +1 @@
+allow-mixed-uninlined-format-args = false
diff --git a/src/tools/clippy/tests/ui-toml/allow_mixed_uninlined_format_args/uninlined_format_args.fixed b/src/tools/clippy/tests/ui-toml/allow_mixed_uninlined_format_args/uninlined_format_args.fixed
new file mode 100644 (file)
index 0000000..aa8b45b
--- /dev/null
@@ -0,0 +1,14 @@
+// run-rustfix
+#![warn(clippy::uninlined_format_args)]
+
+fn main() {
+    let local_i32 = 1;
+    let local_f64 = 2.0;
+    let local_opt: Option<i32> = Some(3);
+
+    println!("val='{local_i32}'");
+    println!("Hello x is {local_f64:.local_i32$}");
+    println!("Hello {local_i32} is {local_f64:.*}", 5);
+    println!("Hello {local_i32} is {local_f64:.*}", 5);
+    println!("{local_i32}, {}", local_opt.unwrap());
+}
diff --git a/src/tools/clippy/tests/ui-toml/allow_mixed_uninlined_format_args/uninlined_format_args.rs b/src/tools/clippy/tests/ui-toml/allow_mixed_uninlined_format_args/uninlined_format_args.rs
new file mode 100644 (file)
index 0000000..ad2e486
--- /dev/null
@@ -0,0 +1,14 @@
+// run-rustfix
+#![warn(clippy::uninlined_format_args)]
+
+fn main() {
+    let local_i32 = 1;
+    let local_f64 = 2.0;
+    let local_opt: Option<i32> = Some(3);
+
+    println!("val='{}'", local_i32);
+    println!("Hello {} is {:.*}", "x", local_i32, local_f64);
+    println!("Hello {} is {:.*}", local_i32, 5, local_f64);
+    println!("Hello {} is {2:.*}", local_i32, 5, local_f64);
+    println!("{}, {}", local_i32, local_opt.unwrap());
+}
diff --git a/src/tools/clippy/tests/ui-toml/allow_mixed_uninlined_format_args/uninlined_format_args.stderr b/src/tools/clippy/tests/ui-toml/allow_mixed_uninlined_format_args/uninlined_format_args.stderr
new file mode 100644 (file)
index 0000000..ee94176
--- /dev/null
@@ -0,0 +1,76 @@
+error: variables can be used directly in the `format!` string
+  --> $DIR/uninlined_format_args.rs:9:5
+   |
+LL |     println!("val='{}'", local_i32);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::uninlined-format-args` implied by `-D warnings`
+help: change this to
+   |
+LL -     println!("val='{}'", local_i32);
+LL +     println!("val='{local_i32}'");
+   |
+
+error: literal with an empty format string
+  --> $DIR/uninlined_format_args.rs:10:35
+   |
+LL |     println!("Hello {} is {:.*}", "x", local_i32, local_f64);
+   |                                   ^^^
+   |
+   = note: `-D clippy::print-literal` implied by `-D warnings`
+help: try this
+   |
+LL -     println!("Hello {} is {:.*}", "x", local_i32, local_f64);
+LL +     println!("Hello x is {:.*}", local_i32, local_f64);
+   |
+
+error: variables can be used directly in the `format!` string
+  --> $DIR/uninlined_format_args.rs:10:5
+   |
+LL |     println!("Hello {} is {:.*}", "x", local_i32, local_f64);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: change this to
+   |
+LL -     println!("Hello {} is {:.*}", "x", local_i32, local_f64);
+LL +     println!("Hello {} is {local_f64:.local_i32$}", "x");
+   |
+
+error: variables can be used directly in the `format!` string
+  --> $DIR/uninlined_format_args.rs:11:5
+   |
+LL |     println!("Hello {} is {:.*}", local_i32, 5, local_f64);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: change this to
+   |
+LL -     println!("Hello {} is {:.*}", local_i32, 5, local_f64);
+LL +     println!("Hello {local_i32} is {local_f64:.*}", 5);
+   |
+
+error: variables can be used directly in the `format!` string
+  --> $DIR/uninlined_format_args.rs:12:5
+   |
+LL |     println!("Hello {} is {2:.*}", local_i32, 5, local_f64);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: change this to
+   |
+LL -     println!("Hello {} is {2:.*}", local_i32, 5, local_f64);
+LL +     println!("Hello {local_i32} is {local_f64:.*}", 5);
+   |
+
+error: variables can be used directly in the `format!` string
+  --> $DIR/uninlined_format_args.rs:13:5
+   |
+LL |     println!("{}, {}", local_i32, local_opt.unwrap());
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: change this to
+   |
+LL -     println!("{}, {}", local_i32, local_opt.unwrap());
+LL +     println!("{local_i32}, {}", local_opt.unwrap());
+   |
+
+error: aborting due to 6 previous errors
+
index f91d285c2e0eefcc3d06aea471a6f5b59a14caa2..01a5e962c9491ea0d52cd89707f4c1d3c3ec4e74 100644 (file)
@@ -1,6 +1,7 @@
 error: error reading Clippy's configuration file `$DIR/clippy.toml`: unknown field `foobar`, expected one of
            allow-dbg-in-tests
            allow-expect-in-tests
+           allow-mixed-uninlined-format-args
            allow-print-in-tests
            allow-unwrap-in-tests
            allowed-scripts
index 079b7c000dce1e7f953418a356fe2f538d44ad61..adcbd4d5134d340180d994835720ee39ec11a9af 100644 (file)
@@ -2,7 +2,6 @@
 // edition:2018
 // aux-build:macro_rules.rs
 
-#![feature(custom_inner_attributes)]
 #![feature(exclusive_range_pattern)]
 #![feature(stmt_expr_attributes)]
 #![warn(clippy::almost_complete_letter_range)]
@@ -62,16 +61,16 @@ fn main() {
     b!();
 }
 
+#[clippy::msrv = "1.25"]
 fn _under_msrv() {
-    #![clippy::msrv = "1.25"]
     let _ = match 'a' {
         'a'...'z' => 1,
         _ => 2,
     };
 }
 
+#[clippy::msrv = "1.26"]
 fn _meets_msrv() {
-    #![clippy::msrv = "1.26"]
     let _ = 'a'..='z';
     let _ = match 'a' {
         'a'..='z' => 1,
index a66900a976efa92d549a8a194c78d3e376a98cdb..9979316eca4290a4d6718cb17182b112c7760257 100644 (file)
@@ -2,7 +2,6 @@
 // edition:2018
 // aux-build:macro_rules.rs
 
-#![feature(custom_inner_attributes)]
 #![feature(exclusive_range_pattern)]
 #![feature(stmt_expr_attributes)]
 #![warn(clippy::almost_complete_letter_range)]
@@ -62,16 +61,16 @@ fn main() {
     b!();
 }
 
+#[clippy::msrv = "1.25"]
 fn _under_msrv() {
-    #![clippy::msrv = "1.25"]
     let _ = match 'a' {
         'a'..'z' => 1,
         _ => 2,
     };
 }
 
+#[clippy::msrv = "1.26"]
 fn _meets_msrv() {
-    #![clippy::msrv = "1.26"]
     let _ = 'a'..'z';
     let _ = match 'a' {
         'a'..'z' => 1,
index 3de44c72c1b9d35ad50773e16b143200162da5dd..9abf6d6c5e7d00c4fea180c6219eb7a3804a4cc2 100644 (file)
@@ -1,5 +1,5 @@
 error: almost complete ascii letter range
-  --> $DIR/almost_complete_letter_range.rs:30:17
+  --> $DIR/almost_complete_letter_range.rs:29:17
    |
 LL |         let _ = ('a') ..'z';
    |                 ^^^^^^--^^^
@@ -9,7 +9,7 @@ LL |         let _ = ('a') ..'z';
    = note: `-D clippy::almost-complete-letter-range` implied by `-D warnings`
 
 error: almost complete ascii letter range
-  --> $DIR/almost_complete_letter_range.rs:31:17
+  --> $DIR/almost_complete_letter_range.rs:30:17
    |
 LL |         let _ = 'A' .. ('Z');
    |                 ^^^^--^^^^^^
@@ -17,7 +17,7 @@ LL |         let _ = 'A' .. ('Z');
    |                     help: use an inclusive range: `..=`
 
 error: almost complete ascii letter range
-  --> $DIR/almost_complete_letter_range.rs:37:13
+  --> $DIR/almost_complete_letter_range.rs:36:13
    |
 LL |     let _ = (b'a')..(b'z');
    |             ^^^^^^--^^^^^^
@@ -25,7 +25,7 @@ LL |     let _ = (b'a')..(b'z');
    |                   help: use an inclusive range: `..=`
 
 error: almost complete ascii letter range
-  --> $DIR/almost_complete_letter_range.rs:38:13
+  --> $DIR/almost_complete_letter_range.rs:37:13
    |
 LL |     let _ = b'A'..b'Z';
    |             ^^^^--^^^^
@@ -33,7 +33,7 @@ LL |     let _ = b'A'..b'Z';
    |                 help: use an inclusive range: `..=`
 
 error: almost complete ascii letter range
-  --> $DIR/almost_complete_letter_range.rs:43:13
+  --> $DIR/almost_complete_letter_range.rs:42:13
    |
 LL |     let _ = a!()..'z';
    |             ^^^^--^^^
@@ -41,7 +41,7 @@ LL |     let _ = a!()..'z';
    |                 help: use an inclusive range: `..=`
 
 error: almost complete ascii letter range
-  --> $DIR/almost_complete_letter_range.rs:46:9
+  --> $DIR/almost_complete_letter_range.rs:45:9
    |
 LL |         b'a'..b'z' if true => 1,
    |         ^^^^--^^^^
@@ -49,7 +49,7 @@ LL |         b'a'..b'z' if true => 1,
    |             help: use an inclusive range: `..=`
 
 error: almost complete ascii letter range
-  --> $DIR/almost_complete_letter_range.rs:47:9
+  --> $DIR/almost_complete_letter_range.rs:46:9
    |
 LL |         b'A'..b'Z' if true => 2,
    |         ^^^^--^^^^
@@ -57,7 +57,7 @@ LL |         b'A'..b'Z' if true => 2,
    |             help: use an inclusive range: `..=`
 
 error: almost complete ascii letter range
-  --> $DIR/almost_complete_letter_range.rs:54:9
+  --> $DIR/almost_complete_letter_range.rs:53:9
    |
 LL |         'a'..'z' if true => 1,
    |         ^^^--^^^
@@ -65,7 +65,7 @@ LL |         'a'..'z' if true => 1,
    |            help: use an inclusive range: `..=`
 
 error: almost complete ascii letter range
-  --> $DIR/almost_complete_letter_range.rs:55:9
+  --> $DIR/almost_complete_letter_range.rs:54:9
    |
 LL |         'A'..'Z' if true => 2,
    |         ^^^--^^^
@@ -73,7 +73,7 @@ LL |         'A'..'Z' if true => 2,
    |            help: use an inclusive range: `..=`
 
 error: almost complete ascii letter range
-  --> $DIR/almost_complete_letter_range.rs:23:17
+  --> $DIR/almost_complete_letter_range.rs:22:17
    |
 LL |         let _ = 'a'..'z';
    |                 ^^^--^^^
@@ -86,7 +86,7 @@ LL |     b!();
    = note: this error originates in the macro `b` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: almost complete ascii letter range
-  --> $DIR/almost_complete_letter_range.rs:68:9
+  --> $DIR/almost_complete_letter_range.rs:67:9
    |
 LL |         'a'..'z' => 1,
    |         ^^^--^^^
@@ -94,7 +94,7 @@ LL |         'a'..'z' => 1,
    |            help: use an inclusive range: `...`
 
 error: almost complete ascii letter range
-  --> $DIR/almost_complete_letter_range.rs:75:13
+  --> $DIR/almost_complete_letter_range.rs:74:13
    |
 LL |     let _ = 'a'..'z';
    |             ^^^--^^^
@@ -102,7 +102,7 @@ LL |     let _ = 'a'..'z';
    |                help: use an inclusive range: `..=`
 
 error: almost complete ascii letter range
-  --> $DIR/almost_complete_letter_range.rs:77:9
+  --> $DIR/almost_complete_letter_range.rs:76:9
    |
 LL |         'a'..'z' => 1,
    |         ^^^--^^^
index e6bf944c7a5ecbb3cc08836e9a236c82b34424b9..8676b562b4f9e864611d290253895122f2e9bf42 100644 (file)
@@ -1,6 +1,5 @@
 // run-rustfix
 
-#![feature(custom_inner_attributes)]
 #![warn(clippy::cast_abs_to_unsigned)]
 #![allow(clippy::uninlined_format_args, unused)]
 
@@ -33,16 +32,14 @@ fn main() {
     let _ = (x as i64 - y as i64).unsigned_abs() as u32;
 }
 
+#[clippy::msrv = "1.50"]
 fn msrv_1_50() {
-    #![clippy::msrv = "1.50"]
-
     let x: i32 = 10;
     assert_eq!(10u32, x.abs() as u32);
 }
 
+#[clippy::msrv = "1.51"]
 fn msrv_1_51() {
-    #![clippy::msrv = "1.51"]
-
     let x: i32 = 10;
     assert_eq!(10u32, x.unsigned_abs());
 }
index c87320b5209db8165714a1a1f7f2b837b6380287..5775af874f8fcec64593fd0915d92202f7f98238 100644 (file)
@@ -1,6 +1,5 @@
 // run-rustfix
 
-#![feature(custom_inner_attributes)]
 #![warn(clippy::cast_abs_to_unsigned)]
 #![allow(clippy::uninlined_format_args, unused)]
 
@@ -33,16 +32,14 @@ fn main() {
     let _ = (x as i64 - y as i64).abs() as u32;
 }
 
+#[clippy::msrv = "1.50"]
 fn msrv_1_50() {
-    #![clippy::msrv = "1.50"]
-
     let x: i32 = 10;
     assert_eq!(10u32, x.abs() as u32);
 }
 
+#[clippy::msrv = "1.51"]
 fn msrv_1_51() {
-    #![clippy::msrv = "1.51"]
-
     let x: i32 = 10;
     assert_eq!(10u32, x.abs() as u32);
 }
index 1b39c554b03845d12d1c13cdfabfc23c48949a79..4668554f4511c2bfc2320d261b883dfcfd7c1636 100644 (file)
@@ -1,5 +1,5 @@
 error: casting the result of `i32::abs()` to u32
-  --> $DIR/cast_abs_to_unsigned.rs:9:18
+  --> $DIR/cast_abs_to_unsigned.rs:8:18
    |
 LL |     let y: u32 = x.abs() as u32;
    |                  ^^^^^^^^^^^^^^ help: replace with: `x.unsigned_abs()`
@@ -7,103 +7,103 @@ LL |     let y: u32 = x.abs() as u32;
    = note: `-D clippy::cast-abs-to-unsigned` implied by `-D warnings`
 
 error: casting the result of `i32::abs()` to usize
-  --> $DIR/cast_abs_to_unsigned.rs:13:20
+  --> $DIR/cast_abs_to_unsigned.rs:12:20
    |
 LL |     let _: usize = a.abs() as usize;
    |                    ^^^^^^^ help: replace with: `a.unsigned_abs()`
 
 error: casting the result of `i32::abs()` to usize
-  --> $DIR/cast_abs_to_unsigned.rs:14:20
+  --> $DIR/cast_abs_to_unsigned.rs:13:20
    |
 LL |     let _: usize = a.abs() as _;
    |                    ^^^^^^^ help: replace with: `a.unsigned_abs()`
 
 error: casting the result of `i32::abs()` to usize
-  --> $DIR/cast_abs_to_unsigned.rs:15:13
+  --> $DIR/cast_abs_to_unsigned.rs:14:13
    |
 LL |     let _ = a.abs() as usize;
    |             ^^^^^^^ help: replace with: `a.unsigned_abs()`
 
 error: casting the result of `i64::abs()` to usize
-  --> $DIR/cast_abs_to_unsigned.rs:18:13
+  --> $DIR/cast_abs_to_unsigned.rs:17:13
    |
 LL |     let _ = a.abs() as usize;
    |             ^^^^^^^ help: replace with: `a.unsigned_abs()`
 
 error: casting the result of `i64::abs()` to u8
-  --> $DIR/cast_abs_to_unsigned.rs:19:13
+  --> $DIR/cast_abs_to_unsigned.rs:18:13
    |
 LL |     let _ = a.abs() as u8;
    |             ^^^^^^^ help: replace with: `a.unsigned_abs()`
 
 error: casting the result of `i64::abs()` to u16
-  --> $DIR/cast_abs_to_unsigned.rs:20:13
+  --> $DIR/cast_abs_to_unsigned.rs:19:13
    |
 LL |     let _ = a.abs() as u16;
    |             ^^^^^^^ help: replace with: `a.unsigned_abs()`
 
 error: casting the result of `i64::abs()` to u32
-  --> $DIR/cast_abs_to_unsigned.rs:21:13
+  --> $DIR/cast_abs_to_unsigned.rs:20:13
    |
 LL |     let _ = a.abs() as u32;
    |             ^^^^^^^ help: replace with: `a.unsigned_abs()`
 
 error: casting the result of `i64::abs()` to u64
-  --> $DIR/cast_abs_to_unsigned.rs:22:13
+  --> $DIR/cast_abs_to_unsigned.rs:21:13
    |
 LL |     let _ = a.abs() as u64;
    |             ^^^^^^^^^^^^^^ help: replace with: `a.unsigned_abs()`
 
 error: casting the result of `i64::abs()` to u128
-  --> $DIR/cast_abs_to_unsigned.rs:23:13
+  --> $DIR/cast_abs_to_unsigned.rs:22:13
    |
 LL |     let _ = a.abs() as u128;
    |             ^^^^^^^ help: replace with: `a.unsigned_abs()`
 
 error: casting the result of `isize::abs()` to usize
-  --> $DIR/cast_abs_to_unsigned.rs:26:13
+  --> $DIR/cast_abs_to_unsigned.rs:25:13
    |
 LL |     let _ = a.abs() as usize;
    |             ^^^^^^^^^^^^^^^^ help: replace with: `a.unsigned_abs()`
 
 error: casting the result of `isize::abs()` to u8
-  --> $DIR/cast_abs_to_unsigned.rs:27:13
+  --> $DIR/cast_abs_to_unsigned.rs:26:13
    |
 LL |     let _ = a.abs() as u8;
    |             ^^^^^^^ help: replace with: `a.unsigned_abs()`
 
 error: casting the result of `isize::abs()` to u16
-  --> $DIR/cast_abs_to_unsigned.rs:28:13
+  --> $DIR/cast_abs_to_unsigned.rs:27:13
    |
 LL |     let _ = a.abs() as u16;
    |             ^^^^^^^ help: replace with: `a.unsigned_abs()`
 
 error: casting the result of `isize::abs()` to u32
-  --> $DIR/cast_abs_to_unsigned.rs:29:13
+  --> $DIR/cast_abs_to_unsigned.rs:28:13
    |
 LL |     let _ = a.abs() as u32;
    |             ^^^^^^^ help: replace with: `a.unsigned_abs()`
 
 error: casting the result of `isize::abs()` to u64
-  --> $DIR/cast_abs_to_unsigned.rs:30:13
+  --> $DIR/cast_abs_to_unsigned.rs:29:13
    |
 LL |     let _ = a.abs() as u64;
    |             ^^^^^^^ help: replace with: `a.unsigned_abs()`
 
 error: casting the result of `isize::abs()` to u128
-  --> $DIR/cast_abs_to_unsigned.rs:31:13
+  --> $DIR/cast_abs_to_unsigned.rs:30:13
    |
 LL |     let _ = a.abs() as u128;
    |             ^^^^^^^ help: replace with: `a.unsigned_abs()`
 
 error: casting the result of `i64::abs()` to u32
-  --> $DIR/cast_abs_to_unsigned.rs:33:13
+  --> $DIR/cast_abs_to_unsigned.rs:32:13
    |
 LL |     let _ = (x as i64 - y as i64).abs() as u32;
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `(x as i64 - y as i64).unsigned_abs()`
 
 error: casting the result of `i32::abs()` to u32
-  --> $DIR/cast_abs_to_unsigned.rs:47:23
+  --> $DIR/cast_abs_to_unsigned.rs:44:23
    |
 LL |     assert_eq!(10u32, x.abs() as u32);
    |                       ^^^^^^^^^^^^^^ help: replace with: `x.unsigned_abs()`
index af13b755e310a55224e5048af11931621070106a..13b3cf838c9f02c2a75ee76b362670a416e945a0 100644 (file)
@@ -1,6 +1,5 @@
 // run-rustfix
 
-#![feature(custom_inner_attributes)]
 #![allow(dead_code)]
 #![warn(clippy::cast_lossless)]
 
@@ -42,14 +41,12 @@ mod cast_lossless_in_impl {
     }
 }
 
+#[clippy::msrv = "1.27"]
 fn msrv_1_27() {
-    #![clippy::msrv = "1.27"]
-
     let _ = true as u8;
 }
 
+#[clippy::msrv = "1.28"]
 fn msrv_1_28() {
-    #![clippy::msrv = "1.28"]
-
     let _ = u8::from(true);
 }
index 3b06af899c60d0a5118b671a8a7066714da9a36d..3eed2135562c8b7c3de500699b97cb06aa3ea50f 100644 (file)
@@ -1,6 +1,5 @@
 // run-rustfix
 
-#![feature(custom_inner_attributes)]
 #![allow(dead_code)]
 #![warn(clippy::cast_lossless)]
 
@@ -42,14 +41,12 @@ pub const fn convert(x: bool) -> u64 {
     }
 }
 
+#[clippy::msrv = "1.27"]
 fn msrv_1_27() {
-    #![clippy::msrv = "1.27"]
-
     let _ = true as u8;
 }
 
+#[clippy::msrv = "1.28"]
 fn msrv_1_28() {
-    #![clippy::msrv = "1.28"]
-
     let _ = true as u8;
 }
index 768b033d10a28add2d6b2383346567d39edd0fc6..ce240b70f891d2624c0a7a1c4ec255106a12a68f 100644 (file)
@@ -1,5 +1,5 @@
 error: casting `bool` to `u8` is more cleanly stated with `u8::from(_)`
-  --> $DIR/cast_lossless_bool.rs:9:13
+  --> $DIR/cast_lossless_bool.rs:8:13
    |
 LL |     let _ = true as u8;
    |             ^^^^^^^^^^ help: try: `u8::from(true)`
@@ -7,79 +7,79 @@ LL |     let _ = true as u8;
    = note: `-D clippy::cast-lossless` implied by `-D warnings`
 
 error: casting `bool` to `u16` is more cleanly stated with `u16::from(_)`
-  --> $DIR/cast_lossless_bool.rs:10:13
+  --> $DIR/cast_lossless_bool.rs:9:13
    |
 LL |     let _ = true as u16;
    |             ^^^^^^^^^^^ help: try: `u16::from(true)`
 
 error: casting `bool` to `u32` is more cleanly stated with `u32::from(_)`
-  --> $DIR/cast_lossless_bool.rs:11:13
+  --> $DIR/cast_lossless_bool.rs:10:13
    |
 LL |     let _ = true as u32;
    |             ^^^^^^^^^^^ help: try: `u32::from(true)`
 
 error: casting `bool` to `u64` is more cleanly stated with `u64::from(_)`
-  --> $DIR/cast_lossless_bool.rs:12:13
+  --> $DIR/cast_lossless_bool.rs:11:13
    |
 LL |     let _ = true as u64;
    |             ^^^^^^^^^^^ help: try: `u64::from(true)`
 
 error: casting `bool` to `u128` is more cleanly stated with `u128::from(_)`
-  --> $DIR/cast_lossless_bool.rs:13:13
+  --> $DIR/cast_lossless_bool.rs:12:13
    |
 LL |     let _ = true as u128;
    |             ^^^^^^^^^^^^ help: try: `u128::from(true)`
 
 error: casting `bool` to `usize` is more cleanly stated with `usize::from(_)`
-  --> $DIR/cast_lossless_bool.rs:14:13
+  --> $DIR/cast_lossless_bool.rs:13:13
    |
 LL |     let _ = true as usize;
    |             ^^^^^^^^^^^^^ help: try: `usize::from(true)`
 
 error: casting `bool` to `i8` is more cleanly stated with `i8::from(_)`
-  --> $DIR/cast_lossless_bool.rs:16:13
+  --> $DIR/cast_lossless_bool.rs:15:13
    |
 LL |     let _ = true as i8;
    |             ^^^^^^^^^^ help: try: `i8::from(true)`
 
 error: casting `bool` to `i16` is more cleanly stated with `i16::from(_)`
-  --> $DIR/cast_lossless_bool.rs:17:13
+  --> $DIR/cast_lossless_bool.rs:16:13
    |
 LL |     let _ = true as i16;
    |             ^^^^^^^^^^^ help: try: `i16::from(true)`
 
 error: casting `bool` to `i32` is more cleanly stated with `i32::from(_)`
-  --> $DIR/cast_lossless_bool.rs:18:13
+  --> $DIR/cast_lossless_bool.rs:17:13
    |
 LL |     let _ = true as i32;
    |             ^^^^^^^^^^^ help: try: `i32::from(true)`
 
 error: casting `bool` to `i64` is more cleanly stated with `i64::from(_)`
-  --> $DIR/cast_lossless_bool.rs:19:13
+  --> $DIR/cast_lossless_bool.rs:18:13
    |
 LL |     let _ = true as i64;
    |             ^^^^^^^^^^^ help: try: `i64::from(true)`
 
 error: casting `bool` to `i128` is more cleanly stated with `i128::from(_)`
-  --> $DIR/cast_lossless_bool.rs:20:13
+  --> $DIR/cast_lossless_bool.rs:19:13
    |
 LL |     let _ = true as i128;
    |             ^^^^^^^^^^^^ help: try: `i128::from(true)`
 
 error: casting `bool` to `isize` is more cleanly stated with `isize::from(_)`
-  --> $DIR/cast_lossless_bool.rs:21:13
+  --> $DIR/cast_lossless_bool.rs:20:13
    |
 LL |     let _ = true as isize;
    |             ^^^^^^^^^^^^^ help: try: `isize::from(true)`
 
 error: casting `bool` to `u16` is more cleanly stated with `u16::from(_)`
-  --> $DIR/cast_lossless_bool.rs:24:13
+  --> $DIR/cast_lossless_bool.rs:23:13
    |
 LL |     let _ = (true | false) as u16;
    |             ^^^^^^^^^^^^^^^^^^^^^ help: try: `u16::from(true | false)`
 
 error: casting `bool` to `u8` is more cleanly stated with `u8::from(_)`
-  --> $DIR/cast_lossless_bool.rs:54:13
+  --> $DIR/cast_lossless_bool.rs:51:13
    |
 LL |     let _ = true as u8;
    |             ^^^^^^^^^^ help: try: `u8::from(true)`
index 8a5645b22ed19ddf82512b2c51944e7f92736555..b970b1209b6546a90fb05658810e029a06a6f8a5 100644 (file)
@@ -1,5 +1,5 @@
 // run-rustfix
-#![feature(stmt_expr_attributes, custom_inner_attributes)]
+#![feature(stmt_expr_attributes)]
 
 #![allow(unused, clippy::no_effect, clippy::unnecessary_operation)]
 #![warn(clippy::deprecated_cfg_attr)]
@@ -30,16 +30,14 @@ mod foo {
     pub fn f() {}
 }
 
+#[clippy::msrv = "1.29"]
 fn msrv_1_29() {
-    #![clippy::msrv = "1.29"]
-
     #[cfg_attr(rustfmt, rustfmt::skip)]
     1+29;
 }
 
+#[clippy::msrv = "1.30"]
 fn msrv_1_30() {
-    #![clippy::msrv = "1.30"]
-
     #[rustfmt::skip]
     1+30;
 }
index 2fb140efae7680085af0ea9eab5c089edb1fd1c6..0a8e6a89d8a0f510a162fbe9ca3d6dcedd028c7d 100644 (file)
@@ -1,5 +1,5 @@
 // run-rustfix
-#![feature(stmt_expr_attributes, custom_inner_attributes)]
+#![feature(stmt_expr_attributes)]
 
 #![allow(unused, clippy::no_effect, clippy::unnecessary_operation)]
 #![warn(clippy::deprecated_cfg_attr)]
@@ -30,16 +30,14 @@ mod foo {
     pub fn f() {}
 }
 
+#[clippy::msrv = "1.29"]
 fn msrv_1_29() {
-    #![clippy::msrv = "1.29"]
-
     #[cfg_attr(rustfmt, rustfmt::skip)]
     1+29;
 }
 
+#[clippy::msrv = "1.30"]
 fn msrv_1_30() {
-    #![clippy::msrv = "1.30"]
-
     #[cfg_attr(rustfmt, rustfmt::skip)]
     1+30;
 }
index 08df7b2b39a0c26569df08e183e2f3a481c9f0d4..524a2bf72484bf1d4a0d1a13dc791cd31385fb4b 100644 (file)
@@ -13,7 +13,7 @@ LL | #[cfg_attr(rustfmt, rustfmt_skip)]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `#[rustfmt::skip]`
 
 error: `cfg_attr` is deprecated for rustfmt and got replaced by tool attributes
-  --> $DIR/cfg_attr_rustfmt.rs:43:5
+  --> $DIR/cfg_attr_rustfmt.rs:41:5
    |
 LL |     #[cfg_attr(rustfmt, rustfmt::skip)]
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `#[rustfmt::skip]`
index f936957cb40c682d7d6bdbb538fddacb07c943fc..e279ba3147bba3420159b3cccb6a0bc5181efda0 100644 (file)
@@ -1,6 +1,5 @@
 // run-rustfix
 
-#![feature(custom_inner_attributes)]
 #![allow(
     clippy::cast_lossless,
     unused,
@@ -78,16 +77,14 @@ pub const fn issue_8898(i: u32) -> bool {
     i <= i32::MAX as u32
 }
 
+#[clippy::msrv = "1.33"]
 fn msrv_1_33() {
-    #![clippy::msrv = "1.33"]
-
     let value: i64 = 33;
     let _ = value <= (u32::MAX as i64) && value >= 0;
 }
 
+#[clippy::msrv = "1.34"]
 fn msrv_1_34() {
-    #![clippy::msrv = "1.34"]
-
     let value: i64 = 34;
     let _ = u32::try_from(value).is_ok();
 }
index 77aec713ff3169079e3562ba9d413116196079d8..9d7a40995c3735b82daecc483e1d566c40a8709e 100644 (file)
@@ -1,6 +1,5 @@
 // run-rustfix
 
-#![feature(custom_inner_attributes)]
 #![allow(
     clippy::cast_lossless,
     unused,
@@ -78,16 +77,14 @@ pub const fn issue_8898(i: u32) -> bool {
     i <= i32::MAX as u32
 }
 
+#[clippy::msrv = "1.33"]
 fn msrv_1_33() {
-    #![clippy::msrv = "1.33"]
-
     let value: i64 = 33;
     let _ = value <= (u32::MAX as i64) && value >= 0;
 }
 
+#[clippy::msrv = "1.34"]
 fn msrv_1_34() {
-    #![clippy::msrv = "1.34"]
-
     let value: i64 = 34;
     let _ = value <= (u32::MAX as i64) && value >= 0;
 }
index b2bf7af8daf87a8df2b6a723a1b72ee53dc882c8..273ead73bda580a27607ef7362eb3654c06efe10 100644 (file)
@@ -1,5 +1,5 @@
 error: checked cast can be simplified
-  --> $DIR/checked_conversions.rs:17:13
+  --> $DIR/checked_conversions.rs:16:13
    |
 LL |     let _ = value <= (u32::max_value() as i64) && value >= 0;
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `u32::try_from(value).is_ok()`
@@ -7,97 +7,97 @@ LL |     let _ = value <= (u32::max_value() as i64) && value >= 0;
    = note: `-D clippy::checked-conversions` implied by `-D warnings`
 
 error: checked cast can be simplified
-  --> $DIR/checked_conversions.rs:18:13
+  --> $DIR/checked_conversions.rs:17:13
    |
 LL |     let _ = value <= (u32::MAX as i64) && value >= 0;
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `u32::try_from(value).is_ok()`
 
 error: checked cast can be simplified
-  --> $DIR/checked_conversions.rs:22:13
+  --> $DIR/checked_conversions.rs:21:13
    |
 LL |     let _ = value <= i64::from(u16::max_value()) && value >= 0;
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `u16::try_from(value).is_ok()`
 
 error: checked cast can be simplified
-  --> $DIR/checked_conversions.rs:23:13
+  --> $DIR/checked_conversions.rs:22:13
    |
 LL |     let _ = value <= i64::from(u16::MAX) && value >= 0;
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `u16::try_from(value).is_ok()`
 
 error: checked cast can be simplified
-  --> $DIR/checked_conversions.rs:27:13
+  --> $DIR/checked_conversions.rs:26:13
    |
 LL |     let _ = value <= (u8::max_value() as isize) && value >= 0;
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `u8::try_from(value).is_ok()`
 
 error: checked cast can be simplified
-  --> $DIR/checked_conversions.rs:28:13
+  --> $DIR/checked_conversions.rs:27:13
    |
 LL |     let _ = value <= (u8::MAX as isize) && value >= 0;
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `u8::try_from(value).is_ok()`
 
 error: checked cast can be simplified
-  --> $DIR/checked_conversions.rs:34:13
+  --> $DIR/checked_conversions.rs:33:13
    |
 LL |     let _ = value <= (i32::max_value() as i64) && value >= (i32::min_value() as i64);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `i32::try_from(value).is_ok()`
 
 error: checked cast can be simplified
-  --> $DIR/checked_conversions.rs:35:13
+  --> $DIR/checked_conversions.rs:34:13
    |
 LL |     let _ = value <= (i32::MAX as i64) && value >= (i32::MIN as i64);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `i32::try_from(value).is_ok()`
 
 error: checked cast can be simplified
-  --> $DIR/checked_conversions.rs:39:13
+  --> $DIR/checked_conversions.rs:38:13
    |
 LL |     let _ = value <= i64::from(i16::max_value()) && value >= i64::from(i16::min_value());
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `i16::try_from(value).is_ok()`
 
 error: checked cast can be simplified
-  --> $DIR/checked_conversions.rs:40:13
+  --> $DIR/checked_conversions.rs:39:13
    |
 LL |     let _ = value <= i64::from(i16::MAX) && value >= i64::from(i16::MIN);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `i16::try_from(value).is_ok()`
 
 error: checked cast can be simplified
-  --> $DIR/checked_conversions.rs:46:13
+  --> $DIR/checked_conversions.rs:45:13
    |
 LL |     let _ = value <= i32::max_value() as u32;
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `i32::try_from(value).is_ok()`
 
 error: checked cast can be simplified
-  --> $DIR/checked_conversions.rs:47:13
+  --> $DIR/checked_conversions.rs:46:13
    |
 LL |     let _ = value <= i32::MAX as u32;
    |             ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `i32::try_from(value).is_ok()`
 
 error: checked cast can be simplified
-  --> $DIR/checked_conversions.rs:51:13
+  --> $DIR/checked_conversions.rs:50:13
    |
 LL |     let _ = value <= isize::max_value() as usize && value as i32 == 5;
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `isize::try_from(value).is_ok()`
 
 error: checked cast can be simplified
-  --> $DIR/checked_conversions.rs:52:13
+  --> $DIR/checked_conversions.rs:51:13
    |
 LL |     let _ = value <= isize::MAX as usize && value as i32 == 5;
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `isize::try_from(value).is_ok()`
 
 error: checked cast can be simplified
-  --> $DIR/checked_conversions.rs:56:13
+  --> $DIR/checked_conversions.rs:55:13
    |
 LL |     let _ = value <= u16::max_value() as u32 && value as i32 == 5;
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `u16::try_from(value).is_ok()`
 
 error: checked cast can be simplified
-  --> $DIR/checked_conversions.rs:57:13
+  --> $DIR/checked_conversions.rs:56:13
    |
 LL |     let _ = value <= u16::MAX as u32 && value as i32 == 5;
    |             ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `u16::try_from(value).is_ok()`
 
 error: checked cast can be simplified
-  --> $DIR/checked_conversions.rs:92:13
+  --> $DIR/checked_conversions.rs:89:13
    |
 LL |     let _ = value <= (u32::MAX as i64) && value >= 0;
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `u32::try_from(value).is_ok()`
index 42ed232d1001cd3dd8c52b3efff71b8d747daab2..ecbfc1feedf62f4f1a8d812bb270d9b9193719cb 100644 (file)
@@ -1,6 +1,5 @@
 // run-rustfix
 
-#![feature(custom_inner_attributes)]
 #![warn(clippy::cloned_instead_of_copied)]
 #![allow(unused)]
 
@@ -17,23 +16,20 @@ fn main() {
     let _ = Some(&String::new()).cloned();
 }
 
+#[clippy::msrv = "1.34"]
 fn msrv_1_34() {
-    #![clippy::msrv = "1.34"]
-
     let _ = [1].iter().cloned();
     let _ = Some(&1).cloned();
 }
 
+#[clippy::msrv = "1.35"]
 fn msrv_1_35() {
-    #![clippy::msrv = "1.35"]
-
     let _ = [1].iter().cloned();
     let _ = Some(&1).copied(); // Option::copied needs 1.35
 }
 
+#[clippy::msrv = "1.36"]
 fn msrv_1_36() {
-    #![clippy::msrv = "1.36"]
-
     let _ = [1].iter().copied(); // Iterator::copied needs 1.36
     let _ = Some(&1).copied();
 }
index 471bd9654cc13371fa01948040fdf25e94a4e60a..163dc3dddce62de3e9d452c0bcc3fa0983196864 100644 (file)
@@ -1,6 +1,5 @@
 // run-rustfix
 
-#![feature(custom_inner_attributes)]
 #![warn(clippy::cloned_instead_of_copied)]
 #![allow(unused)]
 
@@ -17,23 +16,20 @@ fn main() {
     let _ = Some(&String::new()).cloned();
 }
 
+#[clippy::msrv = "1.34"]
 fn msrv_1_34() {
-    #![clippy::msrv = "1.34"]
-
     let _ = [1].iter().cloned();
     let _ = Some(&1).cloned();
 }
 
+#[clippy::msrv = "1.35"]
 fn msrv_1_35() {
-    #![clippy::msrv = "1.35"]
-
     let _ = [1].iter().cloned();
     let _ = Some(&1).cloned(); // Option::copied needs 1.35
 }
 
+#[clippy::msrv = "1.36"]
 fn msrv_1_36() {
-    #![clippy::msrv = "1.36"]
-
     let _ = [1].iter().cloned(); // Iterator::copied needs 1.36
     let _ = Some(&1).cloned();
 }
index 914c9a91e8300e048faf1bc014655c5bc073273f..e0361acd956072d53a704a40f10dd3de1b998f20 100644 (file)
@@ -1,5 +1,5 @@
 error: used `cloned` where `copied` could be used instead
-  --> $DIR/cloned_instead_of_copied.rs:9:24
+  --> $DIR/cloned_instead_of_copied.rs:8:24
    |
 LL |     let _ = [1].iter().cloned();
    |                        ^^^^^^ help: try: `copied`
@@ -7,43 +7,43 @@ LL |     let _ = [1].iter().cloned();
    = note: `-D clippy::cloned-instead-of-copied` implied by `-D warnings`
 
 error: used `cloned` where `copied` could be used instead
-  --> $DIR/cloned_instead_of_copied.rs:10:31
+  --> $DIR/cloned_instead_of_copied.rs:9:31
    |
 LL |     let _ = vec!["hi"].iter().cloned();
    |                               ^^^^^^ help: try: `copied`
 
 error: used `cloned` where `copied` could be used instead
-  --> $DIR/cloned_instead_of_copied.rs:11:22
+  --> $DIR/cloned_instead_of_copied.rs:10:22
    |
 LL |     let _ = Some(&1).cloned();
    |                      ^^^^^^ help: try: `copied`
 
 error: used `cloned` where `copied` could be used instead
-  --> $DIR/cloned_instead_of_copied.rs:12:34
+  --> $DIR/cloned_instead_of_copied.rs:11:34
    |
 LL |     let _ = Box::new([1].iter()).cloned();
    |                                  ^^^^^^ help: try: `copied`
 
 error: used `cloned` where `copied` could be used instead
-  --> $DIR/cloned_instead_of_copied.rs:13:32
+  --> $DIR/cloned_instead_of_copied.rs:12:32
    |
 LL |     let _ = Box::new(Some(&1)).cloned();
    |                                ^^^^^^ help: try: `copied`
 
 error: used `cloned` where `copied` could be used instead
-  --> $DIR/cloned_instead_of_copied.rs:31:22
+  --> $DIR/cloned_instead_of_copied.rs:28:22
    |
 LL |     let _ = Some(&1).cloned(); // Option::copied needs 1.35
    |                      ^^^^^^ help: try: `copied`
 
 error: used `cloned` where `copied` could be used instead
-  --> $DIR/cloned_instead_of_copied.rs:37:24
+  --> $DIR/cloned_instead_of_copied.rs:33:24
    |
 LL |     let _ = [1].iter().cloned(); // Iterator::copied needs 1.36
    |                        ^^^^^^ help: try: `copied`
 
 error: used `cloned` where `copied` could be used instead
-  --> $DIR/cloned_instead_of_copied.rs:38:22
+  --> $DIR/cloned_instead_of_copied.rs:34:22
    |
 LL |     let _ = Some(&1).cloned();
    |                      ^^^^^^ help: try: `copied`
diff --git a/src/tools/clippy/tests/ui/doc_unnecessary_unsafe.rs b/src/tools/clippy/tests/ui/doc_unnecessary_unsafe.rs
deleted file mode 100644 (file)
index d9e9363..0000000
+++ /dev/null
@@ -1,148 +0,0 @@
-// aux-build:doc_unsafe_macros.rs
-
-#![allow(clippy::let_unit_value)]
-
-#[macro_use]
-extern crate doc_unsafe_macros;
-
-/// This is has no safety section, and does not need one either
-pub fn destroy_the_planet() {
-    unimplemented!();
-}
-
-/// This one does not need a `Safety` section
-///
-/// # Safety
-///
-/// This function shouldn't be called unless the horsemen are ready
-pub fn apocalypse(universe: &mut ()) {
-    unimplemented!();
-}
-
-/// This is a private function, skip to match behavior with `missing_safety_doc`.
-///
-/// # Safety
-///
-/// Boo!
-fn you_dont_see_me() {
-    unimplemented!();
-}
-
-mod private_mod {
-    /// This is public but unexported function, skip to match behavior with `missing_safety_doc`.
-    ///
-    /// # Safety
-    ///
-    /// Very safe!
-    pub fn only_crate_wide_accessible() {
-        unimplemented!();
-    }
-
-    /// # Safety
-    ///
-    /// Unnecessary safety!
-    pub fn republished() {
-        unimplemented!();
-    }
-}
-
-pub use private_mod::republished;
-
-pub trait SafeTraitSafeMethods {
-    fn woefully_underdocumented(self);
-
-    /// # Safety
-    ///
-    /// Unnecessary!
-    fn documented(self);
-}
-
-pub trait SafeTrait {
-    fn method();
-}
-
-/// # Safety
-///
-/// Unnecessary!
-pub trait DocumentedSafeTrait {
-    fn method2();
-}
-
-pub struct Struct;
-
-impl SafeTraitSafeMethods for Struct {
-    fn woefully_underdocumented(self) {
-        // all is well
-    }
-
-    fn documented(self) {
-        // all is still well
-    }
-}
-
-impl SafeTrait for Struct {
-    fn method() {}
-}
-
-impl DocumentedSafeTrait for Struct {
-    fn method2() {}
-}
-
-impl Struct {
-    /// # Safety
-    ///
-    /// Unnecessary!
-    pub fn documented() -> Self {
-        unimplemented!();
-    }
-
-    pub fn undocumented(&self) {
-        unimplemented!();
-    }
-
-    /// Private, fine again to stay consistent with `missing_safety_doc`.
-    ///
-    /// # Safety
-    ///
-    /// Unnecessary!
-    fn private(&self) {
-        unimplemented!();
-    }
-}
-
-macro_rules! very_safe {
-    () => {
-        pub fn whee() {
-            unimplemented!()
-        }
-
-        /// # Safety
-        ///
-        /// Driving is very safe already!
-        pub fn drive() {
-            whee()
-        }
-    };
-}
-
-very_safe!();
-
-// we don't lint code from external macros
-undocd_safe!();
-
-fn main() {}
-
-// do not lint if any parent has `#[doc(hidden)]` attribute
-// see #7347
-#[doc(hidden)]
-pub mod __macro {
-    pub struct T;
-    impl T {
-        pub unsafe fn f() {}
-    }
-}
-
-/// # Implementation safety
-pub trait DocumentedSafeTraitWithImplementationHeader {
-    fn method();
-}
diff --git a/src/tools/clippy/tests/ui/doc_unnecessary_unsafe.stderr b/src/tools/clippy/tests/ui/doc_unnecessary_unsafe.stderr
deleted file mode 100644 (file)
index 83b2efb..0000000
+++ /dev/null
@@ -1,51 +0,0 @@
-error: safe function's docs have unnecessary `# Safety` section
-  --> $DIR/doc_unnecessary_unsafe.rs:18:1
-   |
-LL | pub fn apocalypse(universe: &mut ()) {
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: `-D clippy::unnecessary-safety-doc` implied by `-D warnings`
-
-error: safe function's docs have unnecessary `# Safety` section
-  --> $DIR/doc_unnecessary_unsafe.rs:44:5
-   |
-LL |     pub fn republished() {
-   |     ^^^^^^^^^^^^^^^^^^^^
-
-error: safe function's docs have unnecessary `# Safety` section
-  --> $DIR/doc_unnecessary_unsafe.rs:57:5
-   |
-LL |     fn documented(self);
-   |     ^^^^^^^^^^^^^^^^^^^^
-
-error: docs for safe trait have unnecessary `# Safety` section
-  --> $DIR/doc_unnecessary_unsafe.rs:67:1
-   |
-LL | pub trait DocumentedSafeTrait {
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: safe function's docs have unnecessary `# Safety` section
-  --> $DIR/doc_unnecessary_unsafe.rs:95:5
-   |
-LL |     pub fn documented() -> Self {
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: safe function's docs have unnecessary `# Safety` section
-  --> $DIR/doc_unnecessary_unsafe.rs:122:9
-   |
-LL |         pub fn drive() {
-   |         ^^^^^^^^^^^^^^
-...
-LL | very_safe!();
-   | ------------ in this macro invocation
-   |
-   = note: this error originates in the macro `very_safe` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-error: docs for safe trait have unnecessary `# Safety` section
-  --> $DIR/doc_unnecessary_unsafe.rs:146:1
-   |
-LL | pub trait DocumentedSafeTraitWithImplementationHeader {
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: aborting due to 7 previous errors
-
index 3bac738acd65b90412004d73e8719ed885b8c368..b63cbd8a8e6bde03c72dde203720fa44646f548f 100644 (file)
@@ -1,6 +1,5 @@
 // run-rustfix
 
-#![feature(custom_inner_attributes)]
 #![allow(unused)]
 
 struct MyTypeNonDebug;
@@ -16,16 +15,14 @@ fn main() {
     test_non_debug.err().expect("Testing non debug type");
 }
 
+#[clippy::msrv = "1.16"]
 fn msrv_1_16() {
-    #![clippy::msrv = "1.16"]
-
     let x: Result<u32, &str> = Ok(16);
     x.err().expect("16");
 }
 
+#[clippy::msrv = "1.17"]
 fn msrv_1_17() {
-    #![clippy::msrv = "1.17"]
-
     let x: Result<u32, &str> = Ok(17);
     x.expect_err("17");
 }
index 6e7c47d9ad3cf09f49736c3a092577a5d2aed96e..c081a745fb4069b9809a25ab53a2622c40d0ed69 100644 (file)
@@ -1,6 +1,5 @@
 // run-rustfix
 
-#![feature(custom_inner_attributes)]
 #![allow(unused)]
 
 struct MyTypeNonDebug;
@@ -16,16 +15,14 @@ fn main() {
     test_non_debug.err().expect("Testing non debug type");
 }
 
+#[clippy::msrv = "1.16"]
 fn msrv_1_16() {
-    #![clippy::msrv = "1.16"]
-
     let x: Result<u32, &str> = Ok(16);
     x.err().expect("16");
 }
 
+#[clippy::msrv = "1.17"]
 fn msrv_1_17() {
-    #![clippy::msrv = "1.17"]
-
     let x: Result<u32, &str> = Ok(17);
     x.err().expect("17");
 }
index 91a6cf8de65fcd190de086f704fb7d534f374fa3..82c0754cfb00b20ff49202cf9f5510284edf83cf 100644 (file)
@@ -1,5 +1,5 @@
 error: called `.err().expect()` on a `Result` value
-  --> $DIR/err_expect.rs:13:16
+  --> $DIR/err_expect.rs:12:16
    |
 LL |     test_debug.err().expect("Testing debug type");
    |                ^^^^^^^^^^^^ help: try: `expect_err`
@@ -7,7 +7,7 @@ LL |     test_debug.err().expect("Testing debug type");
    = note: `-D clippy::err-expect` implied by `-D warnings`
 
 error: called `.err().expect()` on a `Result` value
-  --> $DIR/err_expect.rs:30:7
+  --> $DIR/err_expect.rs:27:7
    |
 LL |     x.err().expect("17");
    |       ^^^^^^^^^^^^ help: try: `expect_err`
index a9cc80aaaf623c81f85c79be05c1c8b93b6b6ecf..dc129591eac4eb7e4f9e96f9dc64f739acfad0b6 100644 (file)
@@ -316,3 +316,25 @@ pub fn mutable_impl_fn_mut(mut f: impl FnMut(), mut f_used_once: impl FnMut()) -
 
     move || takes_fn_mut(&mut f_used_once)
 }
+
+impl dyn TestTrait + '_ {
+    fn method_on_dyn(&self) -> bool {
+        false
+    }
+}
+
+// https://github.com/rust-lang/rust-clippy/issues/7746
+fn angle_brackets_and_substs() {
+    let array_opt: Option<&[u8; 3]> = Some(&[4, 8, 7]);
+    array_opt.map(<[u8; 3]>::as_slice);
+
+    let slice_opt: Option<&[u8]> = Some(b"slice");
+    slice_opt.map(<[u8]>::len);
+
+    let ptr_opt: Option<*const usize> = Some(&487);
+    ptr_opt.map(<*const usize>::is_null);
+
+    let test_struct = TestStruct { some_ref: &487 };
+    let dyn_opt: Option<&dyn TestTrait> = Some(&test_struct);
+    dyn_opt.map(<dyn TestTrait>::method_on_dyn);
+}
index cc99906ccd6677e29488c732a9a5998842c7b542..025fd6a0b7afdf1f5995c0a9d38f314d28efbb3c 100644 (file)
@@ -316,3 +316,25 @@ fn takes_fn_once(_: impl FnOnce()) {}
 
     move || takes_fn_mut(|| f_used_once())
 }
+
+impl dyn TestTrait + '_ {
+    fn method_on_dyn(&self) -> bool {
+        false
+    }
+}
+
+// https://github.com/rust-lang/rust-clippy/issues/7746
+fn angle_brackets_and_substs() {
+    let array_opt: Option<&[u8; 3]> = Some(&[4, 8, 7]);
+    array_opt.map(|a| a.as_slice());
+
+    let slice_opt: Option<&[u8]> = Some(b"slice");
+    slice_opt.map(|s| s.len());
+
+    let ptr_opt: Option<*const usize> = Some(&487);
+    ptr_opt.map(|p| p.is_null());
+
+    let test_struct = TestStruct { some_ref: &487 };
+    let dyn_opt: Option<&dyn TestTrait> = Some(&test_struct);
+    dyn_opt.map(|d| d.method_on_dyn());
+}
index 434706b7e258f07d70cd75e9523b4807c06a739c..a521fb868607ad8de2aafb9e3085a6b6bfd12f1e 100644 (file)
@@ -134,5 +134,29 @@ error: redundant closure
 LL |     move || takes_fn_mut(|| f_used_once())
    |                          ^^^^^^^^^^^^^^^^ help: replace the closure with the function itself: `&mut f_used_once`
 
-error: aborting due to 22 previous errors
+error: redundant closure
+  --> $DIR/eta.rs:329:19
+   |
+LL |     array_opt.map(|a| a.as_slice());
+   |                   ^^^^^^^^^^^^^^^^ help: replace the closure with the method itself: `<[u8; 3]>::as_slice`
+
+error: redundant closure
+  --> $DIR/eta.rs:332:19
+   |
+LL |     slice_opt.map(|s| s.len());
+   |                   ^^^^^^^^^^^ help: replace the closure with the method itself: `<[u8]>::len`
+
+error: redundant closure
+  --> $DIR/eta.rs:335:17
+   |
+LL |     ptr_opt.map(|p| p.is_null());
+   |                 ^^^^^^^^^^^^^^^ help: replace the closure with the method itself: `<*const usize>::is_null`
+
+error: redundant closure
+  --> $DIR/eta.rs:339:17
+   |
+LL |     dyn_opt.map(|d| d.method_on_dyn());
+   |                 ^^^^^^^^^^^^^^^^^^^^^ help: replace the closure with the method itself: `<dyn TestTrait>::method_on_dyn`
+
+error: aborting due to 26 previous errors
 
index 59ff5e4040a3d6b67443d71ea52f6f8b1eb13ba4..475fae5e823b31e66a484cae692c3ed6ab0ed2b6 100644 (file)
@@ -277,4 +277,8 @@ fn main() {
         unimplemented!()
     }
     let _: String = takes_assoc(&*String::new());
+
+    // Issue #9901
+    fn takes_ref(_: &i32) {}
+    takes_ref(*Box::new(&0i32));
 }
index bcfb60c32788642fafe8e4acedbf326e2ee19c06..c1894258f4d84312d891f55472908489c5173aba 100644 (file)
@@ -277,4 +277,8 @@ fn takes_assoc<T: WithAssoc>(_: &T::Assoc) -> T {
         unimplemented!()
     }
     let _: String = takes_assoc(&*String::new());
+
+    // Issue #9901
+    fn takes_ref(_: &i32) {}
+    takes_ref(*Box::new(&0i32));
 }
index 41828ddd7acde22e0d7ad9e98a7df008a05b5d7f..462d46169fcbec0dff6c86ca1d848df8cee13e5e 100644 (file)
@@ -1,6 +1,5 @@
 // run-rustfix
 
-#![feature(custom_inner_attributes)]
 #![warn(clippy::all, clippy::pedantic)]
 #![allow(unused)]
 
@@ -11,16 +10,14 @@ fn main() {
     assert_eq!(element, Some(1));
 }
 
+#[clippy::msrv = "1.29"]
 fn msrv_1_29() {
-    #![clippy::msrv = "1.29"]
-
     let a = ["1", "lol", "3", "NaN", "5"];
     let _: Option<i32> = a.iter().filter_map(|s| s.parse().ok()).next();
 }
 
+#[clippy::msrv = "1.30"]
 fn msrv_1_30() {
-    #![clippy::msrv = "1.30"]
-
     let a = ["1", "lol", "3", "NaN", "5"];
     let _: Option<i32> = a.iter().find_map(|s| s.parse().ok());
 }
index be492a81b45ec3e638c0087c3108705e55ffd9cb..2ea00cf73072e6abecc95e73dc07c45d2d46da96 100644 (file)
@@ -1,6 +1,5 @@
 // run-rustfix
 
-#![feature(custom_inner_attributes)]
 #![warn(clippy::all, clippy::pedantic)]
 #![allow(unused)]
 
@@ -11,16 +10,14 @@ fn main() {
     assert_eq!(element, Some(1));
 }
 
+#[clippy::msrv = "1.29"]
 fn msrv_1_29() {
-    #![clippy::msrv = "1.29"]
-
     let a = ["1", "lol", "3", "NaN", "5"];
     let _: Option<i32> = a.iter().filter_map(|s| s.parse().ok()).next();
 }
 
+#[clippy::msrv = "1.30"]
 fn msrv_1_30() {
-    #![clippy::msrv = "1.30"]
-
     let a = ["1", "lol", "3", "NaN", "5"];
     let _: Option<i32> = a.iter().filter_map(|s| s.parse().ok()).next();
 }
index e789efeabd5503a16eec2e7d531200f7a8875e1d..a9fc6abe88facbda0ab9009ee0063ed5d14a14db 100644 (file)
@@ -1,5 +1,5 @@
 error: called `filter_map(..).next()` on an `Iterator`. This is more succinctly expressed by calling `.find_map(..)` instead
-  --> $DIR/filter_map_next_fixable.rs:10:32
+  --> $DIR/filter_map_next_fixable.rs:9:32
    |
 LL |     let element: Option<i32> = a.iter().filter_map(|s| s.parse().ok()).next();
    |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `a.iter().find_map(|s| s.parse().ok())`
@@ -7,7 +7,7 @@ LL |     let element: Option<i32> = a.iter().filter_map(|s| s.parse().ok()).next
    = note: `-D clippy::filter-map-next` implied by `-D warnings`
 
 error: called `filter_map(..).next()` on an `Iterator`. This is more succinctly expressed by calling `.find_map(..)` instead
-  --> $DIR/filter_map_next_fixable.rs:25:26
+  --> $DIR/filter_map_next_fixable.rs:22:26
    |
 LL |     let _: Option<i32> = a.iter().filter_map(|s| s.parse().ok()).next();
    |                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `a.iter().find_map(|s| s.parse().ok())`
index 1cf49ca45f494d1eca6d0a02785ca04781747755..125c9a69cd3fd1fdd48f8b7a37d7672d84f18a9a 100644 (file)
@@ -1,6 +1,5 @@
 // run-rustfix
 
-#![feature(custom_inner_attributes)]
 #![warn(clippy::from_over_into)]
 #![allow(unused)]
 
@@ -60,9 +59,8 @@ impl From<String> for A {
     }
 }
 
+#[clippy::msrv = "1.40"]
 fn msrv_1_40() {
-    #![clippy::msrv = "1.40"]
-
     struct FromOverInto<T>(Vec<T>);
 
     impl<T> Into<FromOverInto<T>> for Vec<T> {
@@ -72,9 +70,8 @@ fn msrv_1_40() {
     }
 }
 
+#[clippy::msrv = "1.41"]
 fn msrv_1_41() {
-    #![clippy::msrv = "1.41"]
-
     struct FromOverInto<T>(Vec<T>);
 
     impl<T> From<Vec<T>> for FromOverInto<T> {
index d30f3c3fc92567ba78b18523e3b6aa2b891d5de8..5aa127bfabe4b792a59ab914277c7034d7e06b2b 100644 (file)
@@ -1,6 +1,5 @@
 // run-rustfix
 
-#![feature(custom_inner_attributes)]
 #![warn(clippy::from_over_into)]
 #![allow(unused)]
 
@@ -60,9 +59,8 @@ fn from(s: String) -> A {
     }
 }
 
+#[clippy::msrv = "1.40"]
 fn msrv_1_40() {
-    #![clippy::msrv = "1.40"]
-
     struct FromOverInto<T>(Vec<T>);
 
     impl<T> Into<FromOverInto<T>> for Vec<T> {
@@ -72,9 +70,8 @@ fn into(self) -> FromOverInto<T> {
     }
 }
 
+#[clippy::msrv = "1.41"]
 fn msrv_1_41() {
-    #![clippy::msrv = "1.41"]
-
     struct FromOverInto<T>(Vec<T>);
 
     impl<T> Into<FromOverInto<T>> for Vec<T> {
index 9c2a7c04c3646a84252479dea7e42a15319d9bb8..a1764a5ea12ae8f5deef37156c803d244523c4f0 100644 (file)
@@ -1,5 +1,5 @@
 error: an implementation of `From` is preferred since it gives you `Into<_>` for free where the reverse isn't true
-  --> $DIR/from_over_into.rs:10:1
+  --> $DIR/from_over_into.rs:9:1
    |
 LL | impl Into<StringWrapper> for String {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -13,7 +13,7 @@ LL ~         StringWrapper(val)
    |
 
 error: an implementation of `From` is preferred since it gives you `Into<_>` for free where the reverse isn't true
-  --> $DIR/from_over_into.rs:18:1
+  --> $DIR/from_over_into.rs:17:1
    |
 LL | impl Into<SelfType> for String {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -26,7 +26,7 @@ LL ~         SelfType(String::new())
    |
 
 error: an implementation of `From` is preferred since it gives you `Into<_>` for free where the reverse isn't true
-  --> $DIR/from_over_into.rs:33:1
+  --> $DIR/from_over_into.rs:32:1
    |
 LL | impl Into<SelfKeywords> for X {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -41,7 +41,7 @@ LL ~         let _: X = val;
    |
 
 error: an implementation of `From` is preferred since it gives you `Into<_>` for free where the reverse isn't true
-  --> $DIR/from_over_into.rs:45:1
+  --> $DIR/from_over_into.rs:44:1
    |
 LL | impl core::convert::Into<bool> for crate::ExplicitPaths {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -59,7 +59,7 @@ LL ~         val.0
    |
 
 error: an implementation of `From` is preferred since it gives you `Into<_>` for free where the reverse isn't true
-  --> $DIR/from_over_into.rs:80:5
+  --> $DIR/from_over_into.rs:77:5
    |
 LL |     impl<T> Into<FromOverInto<T>> for Vec<T> {
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
index 3bc3a0395244cea27e73a6bf61aaf0f8690af1c0..0e89fdb0dfa28c028d5c7df3edc22ff125512386 100644 (file)
@@ -1,5 +1,4 @@
 #![warn(clippy::if_then_some_else_none)]
-#![feature(custom_inner_attributes)]
 
 fn main() {
     // Should issue an error.
@@ -66,8 +65,8 @@ fn main() {
     let _ = if foo() { into_some("foo") } else { None };
 }
 
+#[clippy::msrv = "1.49"]
 fn _msrv_1_49() {
-    #![clippy::msrv = "1.49"]
     // `bool::then` was stabilized in 1.50. Do not lint this
     let _ = if foo() {
         println!("true!");
@@ -77,8 +76,8 @@ fn _msrv_1_49() {
     };
 }
 
+#[clippy::msrv = "1.50"]
 fn _msrv_1_50() {
-    #![clippy::msrv = "1.50"]
     let _ = if foo() {
         println!("true!");
         Some(150)
index 24e0b5947f19dd44e436cfddc3bf45c40a816f77..d728a3c31a3ba95fabc9b0fa3d587946a1eb5ab3 100644 (file)
@@ -1,5 +1,5 @@
 error: this could be simplified with `bool::then`
-  --> $DIR/if_then_some_else_none.rs:6:13
+  --> $DIR/if_then_some_else_none.rs:5:13
    |
 LL |       let _ = if foo() {
    |  _____________^
@@ -14,7 +14,7 @@ LL | |     };
    = note: `-D clippy::if-then-some-else-none` implied by `-D warnings`
 
 error: this could be simplified with `bool::then`
-  --> $DIR/if_then_some_else_none.rs:14:13
+  --> $DIR/if_then_some_else_none.rs:13:13
    |
 LL |       let _ = if matches!(true, true) {
    |  _____________^
@@ -28,7 +28,7 @@ LL | |     };
    = help: consider using `bool::then` like: `matches!(true, true).then(|| { /* snippet */ matches!(true, false) })`
 
 error: this could be simplified with `bool::then_some`
-  --> $DIR/if_then_some_else_none.rs:23:28
+  --> $DIR/if_then_some_else_none.rs:22:28
    |
 LL |     let _ = x.and_then(|o| if o < 32 { Some(o) } else { None });
    |                            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -36,7 +36,7 @@ LL |     let _ = x.and_then(|o| if o < 32 { Some(o) } else { None });
    = help: consider using `bool::then_some` like: `(o < 32).then_some(o)`
 
 error: this could be simplified with `bool::then_some`
-  --> $DIR/if_then_some_else_none.rs:27:13
+  --> $DIR/if_then_some_else_none.rs:26:13
    |
 LL |     let _ = if !x { Some(0) } else { None };
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -44,7 +44,7 @@ LL |     let _ = if !x { Some(0) } else { None };
    = 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
+  --> $DIR/if_then_some_else_none.rs:81:13
    |
 LL |       let _ = if foo() {
    |  _____________^
index bf7b6edd0e314732cc71a469a23dc0a130aaa394..61843124ccd91f03e3b4cd760aeccb1b7fc40102 100644 (file)
@@ -1,8 +1,8 @@
 error: `macro_use` attributes are no longer needed in the Rust 2018 edition
-  --> $DIR/macro_use_imports.rs:23:5
+  --> $DIR/macro_use_imports.rs:25:5
    |
 LL |     #[macro_use]
-   |     ^^^^^^^^^^^^ help: remove the attribute and import the macro directly, try: `use mac::{inner::foofoo, inner::try_err};`
+   |     ^^^^^^^^^^^^ help: remove the attribute and import the macro directly, try: `use mac::inner::nested::string_add;`
    |
    = note: `-D clippy::macro-use-imports` implied by `-D warnings`
 
@@ -13,10 +13,10 @@ LL |     #[macro_use]
    |     ^^^^^^^^^^^^ help: remove the attribute and import the macro directly, try: `use mini_mac::ClippyMiniMacroTest;`
 
 error: `macro_use` attributes are no longer needed in the Rust 2018 edition
-  --> $DIR/macro_use_imports.rs:25:5
+  --> $DIR/macro_use_imports.rs:23:5
    |
 LL |     #[macro_use]
-   |     ^^^^^^^^^^^^ help: remove the attribute and import the macro directly, try: `use mac::inner::nested::string_add;`
+   |     ^^^^^^^^^^^^ help: remove the attribute and import the macro directly, try: `use mac::{inner::foofoo, inner::try_err};`
 
 error: `macro_use` attributes are no longer needed in the Rust 2018 edition
   --> $DIR/macro_use_imports.rs:19:5
index 331fd29b74e8edb4bcffddc33b66b3d7948e32d4..f7902e6fd53893b717509873b314486a99da2c56 100644 (file)
@@ -1,4 +1,3 @@
-#![feature(custom_inner_attributes)]
 #![warn(clippy::manual_clamp)]
 #![allow(
     unused,
@@ -304,9 +303,8 @@ fn cmp_min_max(input: i32) -> i32 {
     input * 3
 }
 
+#[clippy::msrv = "1.49"]
 fn msrv_1_49() {
-    #![clippy::msrv = "1.49"]
-
     let (input, min, max) = (0, -1, 2);
     let _ = if input < min {
         min
@@ -317,9 +315,8 @@ fn msrv_1_49() {
     };
 }
 
+#[clippy::msrv = "1.50"]
 fn msrv_1_50() {
-    #![clippy::msrv = "1.50"]
-
     let (input, min, max) = (0, -1, 2);
     let _ = if input < min {
         min
index 70abe28091c94ac5570761805e55f5ecfc21517f..988ad1527e837aa9528ff263f28b526ee062afb0 100644 (file)
@@ -1,5 +1,5 @@
 error: clamp-like pattern without using clamp function
-  --> $DIR/manual_clamp.rs:77:5
+  --> $DIR/manual_clamp.rs:76:5
    |
 LL | /     if x9 < min {
 LL | |         x9 = min;
@@ -13,7 +13,7 @@ LL | |     }
    = note: `-D clippy::manual-clamp` implied by `-D warnings`
 
 error: clamp-like pattern without using clamp function
-  --> $DIR/manual_clamp.rs:92:5
+  --> $DIR/manual_clamp.rs:91:5
    |
 LL | /     if x11 > max {
 LL | |         x11 = max;
@@ -26,7 +26,7 @@ LL | |     }
    = note: clamp will panic if max < min
 
 error: clamp-like pattern without using clamp function
-  --> $DIR/manual_clamp.rs:100:5
+  --> $DIR/manual_clamp.rs:99:5
    |
 LL | /     if min > x12 {
 LL | |         x12 = min;
@@ -39,7 +39,7 @@ LL | |     }
    = note: clamp will panic if max < min
 
 error: clamp-like pattern without using clamp function
-  --> $DIR/manual_clamp.rs:108:5
+  --> $DIR/manual_clamp.rs:107:5
    |
 LL | /     if max < x13 {
 LL | |         x13 = max;
@@ -52,7 +52,7 @@ LL | |     }
    = note: clamp will panic if max < min
 
 error: clamp-like pattern without using clamp function
-  --> $DIR/manual_clamp.rs:162:5
+  --> $DIR/manual_clamp.rs:161:5
    |
 LL | /     if max < x33 {
 LL | |         x33 = max;
@@ -65,7 +65,7 @@ LL | |     }
    = note: clamp will panic if max < min
 
 error: clamp-like pattern without using clamp function
-  --> $DIR/manual_clamp.rs:22:14
+  --> $DIR/manual_clamp.rs:21:14
    |
 LL |       let x0 = if max < input {
    |  ______________^
@@ -80,7 +80,7 @@ LL | |     };
    = note: clamp will panic if max < min
 
 error: clamp-like pattern without using clamp function
-  --> $DIR/manual_clamp.rs:30:14
+  --> $DIR/manual_clamp.rs:29:14
    |
 LL |       let x1 = if input > max {
    |  ______________^
@@ -95,7 +95,7 @@ LL | |     };
    = note: clamp will panic if max < min
 
 error: clamp-like pattern without using clamp function
-  --> $DIR/manual_clamp.rs:38:14
+  --> $DIR/manual_clamp.rs:37:14
    |
 LL |       let x2 = if input < min {
    |  ______________^
@@ -110,7 +110,7 @@ LL | |     };
    = note: clamp will panic if max < min
 
 error: clamp-like pattern without using clamp function
-  --> $DIR/manual_clamp.rs:46:14
+  --> $DIR/manual_clamp.rs:45:14
    |
 LL |       let x3 = if min > input {
    |  ______________^
@@ -125,7 +125,7 @@ LL | |     };
    = note: clamp will panic if max < min
 
 error: clamp-like pattern without using clamp function
-  --> $DIR/manual_clamp.rs:54:14
+  --> $DIR/manual_clamp.rs:53:14
    |
 LL |     let x4 = input.max(min).min(max);
    |              ^^^^^^^^^^^^^^^^^^^^^^^ help: replace with clamp: `input.clamp(min, max)`
@@ -133,7 +133,7 @@ LL |     let x4 = input.max(min).min(max);
    = note: clamp will panic if max < min
 
 error: clamp-like pattern without using clamp function
-  --> $DIR/manual_clamp.rs:56:14
+  --> $DIR/manual_clamp.rs:55:14
    |
 LL |     let x5 = input.min(max).max(min);
    |              ^^^^^^^^^^^^^^^^^^^^^^^ help: replace with clamp: `input.clamp(min, max)`
@@ -141,7 +141,7 @@ LL |     let x5 = input.min(max).max(min);
    = note: clamp will panic if max < min
 
 error: clamp-like pattern without using clamp function
-  --> $DIR/manual_clamp.rs:58:14
+  --> $DIR/manual_clamp.rs:57:14
    |
 LL |       let x6 = match input {
    |  ______________^
@@ -154,7 +154,7 @@ LL | |     };
    = note: clamp will panic if max < min
 
 error: clamp-like pattern without using clamp function
-  --> $DIR/manual_clamp.rs:64:14
+  --> $DIR/manual_clamp.rs:63:14
    |
 LL |       let x7 = match input {
    |  ______________^
@@ -167,7 +167,7 @@ LL | |     };
    = note: clamp will panic if max < min
 
 error: clamp-like pattern without using clamp function
-  --> $DIR/manual_clamp.rs:70:14
+  --> $DIR/manual_clamp.rs:69:14
    |
 LL |       let x8 = match input {
    |  ______________^
@@ -180,7 +180,7 @@ LL | |     };
    = note: clamp will panic if max < min
 
 error: clamp-like pattern without using clamp function
-  --> $DIR/manual_clamp.rs:84:15
+  --> $DIR/manual_clamp.rs:83:15
    |
 LL |       let x10 = match input {
    |  _______________^
@@ -193,7 +193,7 @@ LL | |     };
    = note: clamp will panic if max < min
 
 error: clamp-like pattern without using clamp function
-  --> $DIR/manual_clamp.rs:115:15
+  --> $DIR/manual_clamp.rs:114:15
    |
 LL |       let x14 = if input > CONST_MAX {
    |  _______________^
@@ -208,7 +208,7 @@ LL | |     };
    = note: clamp will panic if max < min
 
 error: clamp-like pattern without using clamp function
-  --> $DIR/manual_clamp.rs:124:19
+  --> $DIR/manual_clamp.rs:123:19
    |
 LL |           let x15 = if input > max {
    |  ___________________^
@@ -224,7 +224,7 @@ LL | |         };
    = note: clamp returns NaN if the input is NaN
 
 error: clamp-like pattern without using clamp function
-  --> $DIR/manual_clamp.rs:135:19
+  --> $DIR/manual_clamp.rs:134:19
    |
 LL |         let x16 = cmp_max(cmp_min(input, CONST_MAX), CONST_MIN);
    |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with clamp: `input.clamp(CONST_MIN, CONST_MAX)`
@@ -232,7 +232,7 @@ LL |         let x16 = cmp_max(cmp_min(input, CONST_MAX), CONST_MIN);
    = note: clamp will panic if max < min
 
 error: clamp-like pattern without using clamp function
-  --> $DIR/manual_clamp.rs:136:19
+  --> $DIR/manual_clamp.rs:135:19
    |
 LL |         let x17 = cmp_min(cmp_max(input, CONST_MIN), CONST_MAX);
    |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with clamp: `input.clamp(CONST_MIN, CONST_MAX)`
@@ -240,7 +240,7 @@ LL |         let x17 = cmp_min(cmp_max(input, CONST_MIN), CONST_MAX);
    = note: clamp will panic if max < min
 
 error: clamp-like pattern without using clamp function
-  --> $DIR/manual_clamp.rs:137:19
+  --> $DIR/manual_clamp.rs:136:19
    |
 LL |         let x18 = cmp_max(CONST_MIN, cmp_min(input, CONST_MAX));
    |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with clamp: `input.clamp(CONST_MIN, CONST_MAX)`
@@ -248,7 +248,7 @@ LL |         let x18 = cmp_max(CONST_MIN, cmp_min(input, CONST_MAX));
    = note: clamp will panic if max < min
 
 error: clamp-like pattern without using clamp function
-  --> $DIR/manual_clamp.rs:138:19
+  --> $DIR/manual_clamp.rs:137:19
    |
 LL |         let x19 = cmp_min(CONST_MAX, cmp_max(input, CONST_MIN));
    |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with clamp: `input.clamp(CONST_MIN, CONST_MAX)`
@@ -256,7 +256,7 @@ LL |         let x19 = cmp_min(CONST_MAX, cmp_max(input, CONST_MIN));
    = note: clamp will panic if max < min
 
 error: clamp-like pattern without using clamp function
-  --> $DIR/manual_clamp.rs:139:19
+  --> $DIR/manual_clamp.rs:138:19
    |
 LL |         let x20 = cmp_max(cmp_min(CONST_MAX, input), CONST_MIN);
    |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with clamp: `input.clamp(CONST_MIN, CONST_MAX)`
@@ -264,7 +264,7 @@ LL |         let x20 = cmp_max(cmp_min(CONST_MAX, input), CONST_MIN);
    = note: clamp will panic if max < min
 
 error: clamp-like pattern without using clamp function
-  --> $DIR/manual_clamp.rs:140:19
+  --> $DIR/manual_clamp.rs:139:19
    |
 LL |         let x21 = cmp_min(cmp_max(CONST_MIN, input), CONST_MAX);
    |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with clamp: `input.clamp(CONST_MIN, CONST_MAX)`
@@ -272,7 +272,7 @@ LL |         let x21 = cmp_min(cmp_max(CONST_MIN, input), CONST_MAX);
    = note: clamp will panic if max < min
 
 error: clamp-like pattern without using clamp function
-  --> $DIR/manual_clamp.rs:141:19
+  --> $DIR/manual_clamp.rs:140:19
    |
 LL |         let x22 = cmp_max(CONST_MIN, cmp_min(CONST_MAX, input));
    |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with clamp: `input.clamp(CONST_MIN, CONST_MAX)`
@@ -280,7 +280,7 @@ LL |         let x22 = cmp_max(CONST_MIN, cmp_min(CONST_MAX, input));
    = note: clamp will panic if max < min
 
 error: clamp-like pattern without using clamp function
-  --> $DIR/manual_clamp.rs:142:19
+  --> $DIR/manual_clamp.rs:141:19
    |
 LL |         let x23 = cmp_min(CONST_MAX, cmp_max(CONST_MIN, input));
    |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with clamp: `input.clamp(CONST_MIN, CONST_MAX)`
@@ -288,7 +288,7 @@ LL |         let x23 = cmp_min(CONST_MAX, cmp_max(CONST_MIN, input));
    = note: clamp will panic if max < min
 
 error: clamp-like pattern without using clamp function
-  --> $DIR/manual_clamp.rs:144:19
+  --> $DIR/manual_clamp.rs:143:19
    |
 LL |         let x24 = f64::max(f64::min(input, CONST_F64_MAX), CONST_F64_MIN);
    |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with clamp: `input.clamp(CONST_F64_MIN, CONST_F64_MAX)`
@@ -297,7 +297,7 @@ LL |         let x24 = f64::max(f64::min(input, CONST_F64_MAX), CONST_F64_MIN);
    = note: clamp returns NaN if the input is NaN
 
 error: clamp-like pattern without using clamp function
-  --> $DIR/manual_clamp.rs:145:19
+  --> $DIR/manual_clamp.rs:144:19
    |
 LL |         let x25 = f64::min(f64::max(input, CONST_F64_MIN), CONST_F64_MAX);
    |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with clamp: `input.clamp(CONST_F64_MIN, CONST_F64_MAX)`
@@ -306,7 +306,7 @@ LL |         let x25 = f64::min(f64::max(input, CONST_F64_MIN), CONST_F64_MAX);
    = note: clamp returns NaN if the input is NaN
 
 error: clamp-like pattern without using clamp function
-  --> $DIR/manual_clamp.rs:146:19
+  --> $DIR/manual_clamp.rs:145:19
    |
 LL |         let x26 = f64::max(CONST_F64_MIN, f64::min(input, CONST_F64_MAX));
    |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with clamp: `input.clamp(CONST_F64_MIN, CONST_F64_MAX)`
@@ -315,7 +315,7 @@ LL |         let x26 = f64::max(CONST_F64_MIN, f64::min(input, CONST_F64_MAX));
    = note: clamp returns NaN if the input is NaN
 
 error: clamp-like pattern without using clamp function
-  --> $DIR/manual_clamp.rs:147:19
+  --> $DIR/manual_clamp.rs:146:19
    |
 LL |         let x27 = f64::min(CONST_F64_MAX, f64::max(input, CONST_F64_MIN));
    |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with clamp: `input.clamp(CONST_F64_MIN, CONST_F64_MAX)`
@@ -324,7 +324,7 @@ LL |         let x27 = f64::min(CONST_F64_MAX, f64::max(input, CONST_F64_MIN));
    = note: clamp returns NaN if the input is NaN
 
 error: clamp-like pattern without using clamp function
-  --> $DIR/manual_clamp.rs:148:19
+  --> $DIR/manual_clamp.rs:147:19
    |
 LL |         let x28 = f64::max(f64::min(CONST_F64_MAX, input), CONST_F64_MIN);
    |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with clamp: `input.clamp(CONST_F64_MIN, CONST_F64_MAX)`
@@ -333,7 +333,7 @@ LL |         let x28 = f64::max(f64::min(CONST_F64_MAX, input), CONST_F64_MIN);
    = note: clamp returns NaN if the input is NaN
 
 error: clamp-like pattern without using clamp function
-  --> $DIR/manual_clamp.rs:149:19
+  --> $DIR/manual_clamp.rs:148:19
    |
 LL |         let x29 = f64::min(f64::max(CONST_F64_MIN, input), CONST_F64_MAX);
    |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with clamp: `input.clamp(CONST_F64_MIN, CONST_F64_MAX)`
@@ -342,7 +342,7 @@ LL |         let x29 = f64::min(f64::max(CONST_F64_MIN, input), CONST_F64_MAX);
    = note: clamp returns NaN if the input is NaN
 
 error: clamp-like pattern without using clamp function
-  --> $DIR/manual_clamp.rs:150:19
+  --> $DIR/manual_clamp.rs:149:19
    |
 LL |         let x30 = f64::max(CONST_F64_MIN, f64::min(CONST_F64_MAX, input));
    |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with clamp: `input.clamp(CONST_F64_MIN, CONST_F64_MAX)`
@@ -351,7 +351,7 @@ LL |         let x30 = f64::max(CONST_F64_MIN, f64::min(CONST_F64_MAX, input));
    = note: clamp returns NaN if the input is NaN
 
 error: clamp-like pattern without using clamp function
-  --> $DIR/manual_clamp.rs:151:19
+  --> $DIR/manual_clamp.rs:150:19
    |
 LL |         let x31 = f64::min(CONST_F64_MAX, f64::max(CONST_F64_MIN, input));
    |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with clamp: `input.clamp(CONST_F64_MIN, CONST_F64_MAX)`
@@ -360,7 +360,7 @@ LL |         let x31 = f64::min(CONST_F64_MAX, f64::max(CONST_F64_MIN, input));
    = note: clamp returns NaN if the input is NaN
 
 error: clamp-like pattern without using clamp function
-  --> $DIR/manual_clamp.rs:154:5
+  --> $DIR/manual_clamp.rs:153:5
    |
 LL | /     if x32 < min {
 LL | |         x32 = min;
@@ -372,7 +372,7 @@ LL | |     }
    = note: clamp will panic if max < min
 
 error: clamp-like pattern without using clamp function
-  --> $DIR/manual_clamp.rs:324:13
+  --> $DIR/manual_clamp.rs:321:13
    |
 LL |       let _ = if input < min {
    |  _____________^
index 765bb785994e21275752475450dc439b3e4e2300..231ba83b1426130a3b6482d8e9cb938aacfced4d 100644 (file)
@@ -1,6 +1,5 @@
 // run-rustfix
 
-#![feature(custom_inner_attributes)]
 #![allow(unused, dead_code)]
 #![warn(clippy::manual_is_ascii_check)]
 
@@ -18,28 +17,26 @@ fn main() {
     assert!(matches!('x', 'A'..='Z' | 'a'..='z' | '_'));
 }
 
+#[clippy::msrv = "1.23"]
 fn msrv_1_23() {
-    #![clippy::msrv = "1.23"]
-
     assert!(matches!(b'1', b'0'..=b'9'));
     assert!(matches!('X', 'A'..='Z'));
     assert!(matches!('x', 'A'..='Z' | 'a'..='z'));
 }
 
+#[clippy::msrv = "1.24"]
 fn msrv_1_24() {
-    #![clippy::msrv = "1.24"]
-
     assert!(b'1'.is_ascii_digit());
     assert!('X'.is_ascii_uppercase());
     assert!('x'.is_ascii_alphabetic());
 }
 
+#[clippy::msrv = "1.46"]
 fn msrv_1_46() {
-    #![clippy::msrv = "1.46"]
     const FOO: bool = matches!('x', '0'..='9');
 }
 
+#[clippy::msrv = "1.47"]
 fn msrv_1_47() {
-    #![clippy::msrv = "1.47"]
     const FOO: bool = 'x'.is_ascii_digit();
 }
index be133161041234b251968cafde2e28208c80027b..39ee6151c56f08ff53b77377e9eb916b437d00a6 100644 (file)
@@ -1,6 +1,5 @@
 // run-rustfix
 
-#![feature(custom_inner_attributes)]
 #![allow(unused, dead_code)]
 #![warn(clippy::manual_is_ascii_check)]
 
@@ -18,28 +17,26 @@ fn main() {
     assert!(matches!('x', 'A'..='Z' | 'a'..='z' | '_'));
 }
 
+#[clippy::msrv = "1.23"]
 fn msrv_1_23() {
-    #![clippy::msrv = "1.23"]
-
     assert!(matches!(b'1', b'0'..=b'9'));
     assert!(matches!('X', 'A'..='Z'));
     assert!(matches!('x', 'A'..='Z' | 'a'..='z'));
 }
 
+#[clippy::msrv = "1.24"]
 fn msrv_1_24() {
-    #![clippy::msrv = "1.24"]
-
     assert!(matches!(b'1', b'0'..=b'9'));
     assert!(matches!('X', 'A'..='Z'));
     assert!(matches!('x', 'A'..='Z' | 'a'..='z'));
 }
 
+#[clippy::msrv = "1.46"]
 fn msrv_1_46() {
-    #![clippy::msrv = "1.46"]
     const FOO: bool = matches!('x', '0'..='9');
 }
 
+#[clippy::msrv = "1.47"]
 fn msrv_1_47() {
-    #![clippy::msrv = "1.47"]
     const FOO: bool = matches!('x', '0'..='9');
 }
index c0a9d4db1a15960f9d47c605c6321b087c270e17..397cbe05c822ad7fba97b5f46d02fd569e2882fe 100644 (file)
@@ -1,5 +1,5 @@
 error: manual check for common ascii range
-  --> $DIR/manual_is_ascii_check.rs:8:13
+  --> $DIR/manual_is_ascii_check.rs:7:13
    |
 LL |     assert!(matches!('x', 'a'..='z'));
    |             ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `'x'.is_ascii_lowercase()`
@@ -7,61 +7,61 @@ LL |     assert!(matches!('x', 'a'..='z'));
    = note: `-D clippy::manual-is-ascii-check` implied by `-D warnings`
 
 error: manual check for common ascii range
-  --> $DIR/manual_is_ascii_check.rs:9:13
+  --> $DIR/manual_is_ascii_check.rs:8:13
    |
 LL |     assert!(matches!('X', 'A'..='Z'));
    |             ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `'X'.is_ascii_uppercase()`
 
 error: manual check for common ascii range
-  --> $DIR/manual_is_ascii_check.rs:10:13
+  --> $DIR/manual_is_ascii_check.rs:9:13
    |
 LL |     assert!(matches!(b'x', b'a'..=b'z'));
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `b'x'.is_ascii_lowercase()`
 
 error: manual check for common ascii range
-  --> $DIR/manual_is_ascii_check.rs:11:13
+  --> $DIR/manual_is_ascii_check.rs:10:13
    |
 LL |     assert!(matches!(b'X', b'A'..=b'Z'));
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `b'X'.is_ascii_uppercase()`
 
 error: manual check for common ascii range
-  --> $DIR/manual_is_ascii_check.rs:14:13
+  --> $DIR/manual_is_ascii_check.rs:13:13
    |
 LL |     assert!(matches!(num, '0'..='9'));
    |             ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `num.is_ascii_digit()`
 
 error: manual check for common ascii range
-  --> $DIR/manual_is_ascii_check.rs:15:13
+  --> $DIR/manual_is_ascii_check.rs:14:13
    |
 LL |     assert!(matches!(b'1', b'0'..=b'9'));
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `b'1'.is_ascii_digit()`
 
 error: manual check for common ascii range
-  --> $DIR/manual_is_ascii_check.rs:16:13
+  --> $DIR/manual_is_ascii_check.rs:15:13
    |
 LL |     assert!(matches!('x', 'A'..='Z' | 'a'..='z'));
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `'x'.is_ascii_alphabetic()`
 
 error: manual check for common ascii range
-  --> $DIR/manual_is_ascii_check.rs:32:13
+  --> $DIR/manual_is_ascii_check.rs:29:13
    |
 LL |     assert!(matches!(b'1', b'0'..=b'9'));
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `b'1'.is_ascii_digit()`
 
 error: manual check for common ascii range
-  --> $DIR/manual_is_ascii_check.rs:33:13
+  --> $DIR/manual_is_ascii_check.rs:30:13
    |
 LL |     assert!(matches!('X', 'A'..='Z'));
    |             ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `'X'.is_ascii_uppercase()`
 
 error: manual check for common ascii range
-  --> $DIR/manual_is_ascii_check.rs:34:13
+  --> $DIR/manual_is_ascii_check.rs:31:13
    |
 LL |     assert!(matches!('x', 'A'..='Z' | 'a'..='z'));
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `'x'.is_ascii_alphabetic()`
 
 error: manual check for common ascii range
-  --> $DIR/manual_is_ascii_check.rs:44:23
+  --> $DIR/manual_is_ascii_check.rs:41:23
    |
 LL |     const FOO: bool = matches!('x', '0'..='9');
    |                       ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `'x'.is_ascii_digit()`
index 2ef40e5911af46d077b302bcb78e787bce50b5d4..48a162c13602ca800b3fcfd8f2392b01181b94fb 100644 (file)
@@ -234,4 +234,18 @@ macro_rules! create_binding_if_some_nf {
     // If a type annotation is present, don't lint as
     // expressing the type might be too hard
     let v: () = if let Some(v_some) = g() { v_some } else { panic!() };
+
+    // Issue 9940
+    // Suggestion should not expand macros
+    macro_rules! macro_call {
+        () => {
+            return ()
+        };
+    }
+
+    let ff = Some(1);
+    let _ = match ff {
+        Some(value) => value,
+        _ => macro_call!(),
+    };
 }
index 453b68b8bd003c8f43cadd240412ff0a146ad07b..52aac6bc673d195500f6f3ddf84fccacdd9aa65b 100644 (file)
@@ -259,5 +259,14 @@ LL |     create_binding_if_some!(w, g());
    |
    = note: this error originates in the macro `create_binding_if_some` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error: aborting due to 17 previous errors
+error: this could be rewritten as `let...else`
+  --> $DIR/manual_let_else.rs:247:5
+   |
+LL | /     let _ = match ff {
+LL | |         Some(value) => value,
+LL | |         _ => macro_call!(),
+LL | |     };
+   | |______^ help: consider writing: `let Some(value) = ff else { macro_call!() };`
+
+error: aborting due to 18 previous errors
 
index b942fbfe93056aa45c24dc06c12678db0be8a202..4cdc0546a7446ab6176a759ed867d6048ccb0bad 100644 (file)
@@ -1,7 +1,6 @@
 // run-rustfix
 // aux-build:macro_rules.rs
 
-#![feature(custom_inner_attributes)]
 #![warn(clippy::manual_rem_euclid)]
 
 #[macro_use]
@@ -55,31 +54,27 @@ pub const fn const_rem_euclid_4(num: i32) -> i32 {
     num.rem_euclid(4)
 }
 
+#[clippy::msrv = "1.37"]
 pub fn msrv_1_37() {
-    #![clippy::msrv = "1.37"]
-
     let x: i32 = 10;
     let _: i32 = ((x % 4) + 4) % 4;
 }
 
+#[clippy::msrv = "1.38"]
 pub fn msrv_1_38() {
-    #![clippy::msrv = "1.38"]
-
     let x: i32 = 10;
     let _: i32 = x.rem_euclid(4);
 }
 
 // For const fns:
+#[clippy::msrv = "1.51"]
 pub const fn msrv_1_51() {
-    #![clippy::msrv = "1.51"]
-
     let x: i32 = 10;
     let _: i32 = ((x % 4) + 4) % 4;
 }
 
+#[clippy::msrv = "1.52"]
 pub const fn msrv_1_52() {
-    #![clippy::msrv = "1.52"]
-
     let x: i32 = 10;
     let _: i32 = x.rem_euclid(4);
 }
index 7462d532169f6fb890a4b62131821330fdd96b04..58a9e20f38b1375c3fba248fa4b0321af34e8270 100644 (file)
@@ -1,7 +1,6 @@
 // run-rustfix
 // aux-build:macro_rules.rs
 
-#![feature(custom_inner_attributes)]
 #![warn(clippy::manual_rem_euclid)]
 
 #[macro_use]
@@ -55,31 +54,27 @@ pub const fn const_rem_euclid_4(num: i32) -> i32 {
     ((num % 4) + 4) % 4
 }
 
+#[clippy::msrv = "1.37"]
 pub fn msrv_1_37() {
-    #![clippy::msrv = "1.37"]
-
     let x: i32 = 10;
     let _: i32 = ((x % 4) + 4) % 4;
 }
 
+#[clippy::msrv = "1.38"]
 pub fn msrv_1_38() {
-    #![clippy::msrv = "1.38"]
-
     let x: i32 = 10;
     let _: i32 = ((x % 4) + 4) % 4;
 }
 
 // For const fns:
+#[clippy::msrv = "1.51"]
 pub const fn msrv_1_51() {
-    #![clippy::msrv = "1.51"]
-
     let x: i32 = 10;
     let _: i32 = ((x % 4) + 4) % 4;
 }
 
+#[clippy::msrv = "1.52"]
 pub const fn msrv_1_52() {
-    #![clippy::msrv = "1.52"]
-
     let x: i32 = 10;
     let _: i32 = ((x % 4) + 4) % 4;
 }
index d51bac03b565afaa278696da4742e04fc6a894da..e3122a588b64d1d4a2d204eadcc06223c009a27b 100644 (file)
@@ -1,5 +1,5 @@
 error: manual `rem_euclid` implementation
-  --> $DIR/manual_rem_euclid.rs:20:18
+  --> $DIR/manual_rem_euclid.rs:19:18
    |
 LL |     let _: i32 = ((value % 4) + 4) % 4;
    |                  ^^^^^^^^^^^^^^^^^^^^^ help: consider using: `value.rem_euclid(4)`
@@ -7,31 +7,31 @@ LL |     let _: i32 = ((value % 4) + 4) % 4;
    = note: `-D clippy::manual-rem-euclid` implied by `-D warnings`
 
 error: manual `rem_euclid` implementation
-  --> $DIR/manual_rem_euclid.rs:21:18
+  --> $DIR/manual_rem_euclid.rs:20:18
    |
 LL |     let _: i32 = (4 + (value % 4)) % 4;
    |                  ^^^^^^^^^^^^^^^^^^^^^ help: consider using: `value.rem_euclid(4)`
 
 error: manual `rem_euclid` implementation
-  --> $DIR/manual_rem_euclid.rs:22:18
+  --> $DIR/manual_rem_euclid.rs:21:18
    |
 LL |     let _: i32 = (value % 4 + 4) % 4;
    |                  ^^^^^^^^^^^^^^^^^^^ help: consider using: `value.rem_euclid(4)`
 
 error: manual `rem_euclid` implementation
-  --> $DIR/manual_rem_euclid.rs:23:18
+  --> $DIR/manual_rem_euclid.rs:22:18
    |
 LL |     let _: i32 = (4 + value % 4) % 4;
    |                  ^^^^^^^^^^^^^^^^^^^ help: consider using: `value.rem_euclid(4)`
 
 error: manual `rem_euclid` implementation
-  --> $DIR/manual_rem_euclid.rs:24:22
+  --> $DIR/manual_rem_euclid.rs:23:22
    |
 LL |     let _: i32 = 1 + (4 + value % 4) % 4;
    |                      ^^^^^^^^^^^^^^^^^^^ help: consider using: `value.rem_euclid(4)`
 
 error: manual `rem_euclid` implementation
-  --> $DIR/manual_rem_euclid.rs:13:22
+  --> $DIR/manual_rem_euclid.rs:12:22
    |
 LL |         let _: i32 = ((value % 4) + 4) % 4;
    |                      ^^^^^^^^^^^^^^^^^^^^^ help: consider using: `value.rem_euclid(4)`
@@ -42,25 +42,25 @@ LL |     internal_rem_euclid!();
    = note: this error originates in the macro `internal_rem_euclid` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: manual `rem_euclid` implementation
-  --> $DIR/manual_rem_euclid.rs:50:5
+  --> $DIR/manual_rem_euclid.rs:49:5
    |
 LL |     ((num % 4) + 4) % 4
    |     ^^^^^^^^^^^^^^^^^^^ help: consider using: `num.rem_euclid(4)`
 
 error: manual `rem_euclid` implementation
-  --> $DIR/manual_rem_euclid.rs:55:5
+  --> $DIR/manual_rem_euclid.rs:54:5
    |
 LL |     ((num % 4) + 4) % 4
    |     ^^^^^^^^^^^^^^^^^^^ help: consider using: `num.rem_euclid(4)`
 
 error: manual `rem_euclid` implementation
-  --> $DIR/manual_rem_euclid.rs:69:18
+  --> $DIR/manual_rem_euclid.rs:66:18
    |
 LL |     let _: i32 = ((x % 4) + 4) % 4;
    |                  ^^^^^^^^^^^^^^^^^ help: consider using: `x.rem_euclid(4)`
 
 error: manual `rem_euclid` implementation
-  --> $DIR/manual_rem_euclid.rs:84:18
+  --> $DIR/manual_rem_euclid.rs:79:18
    |
 LL |     let _: i32 = ((x % 4) + 4) % 4;
    |                  ^^^^^^^^^^^^^^^^^ help: consider using: `x.rem_euclid(4)`
index fba503a20667ac4d7c35a9456aef5296f4e558e1..e5ae3cf3e5033295b16936b7f71fac65269834f7 100644 (file)
@@ -1,5 +1,4 @@
 // run-rustfix
-#![feature(custom_inner_attributes)]
 #![warn(clippy::manual_retain)]
 #![allow(unused)]
 use std::collections::BTreeMap;
@@ -216,8 +215,8 @@ fn vec_deque_retain() {
     bar = foobar.into_iter().filter(|x| x % 2 == 0).collect();
 }
 
+#[clippy::msrv = "1.52"]
 fn _msrv_153() {
-    #![clippy::msrv = "1.52"]
     let mut btree_map: BTreeMap<i8, i8> = (0..8).map(|x| (x, x * 10)).collect();
     btree_map = btree_map.into_iter().filter(|(k, _)| k % 2 == 0).collect();
 
@@ -225,14 +224,14 @@ fn _msrv_153() {
     btree_set = btree_set.iter().filter(|&x| x % 2 == 0).copied().collect();
 }
 
+#[clippy::msrv = "1.25"]
 fn _msrv_126() {
-    #![clippy::msrv = "1.25"]
     let mut s = String::from("foobar");
     s = s.chars().filter(|&c| c != 'o').to_owned().collect();
 }
 
+#[clippy::msrv = "1.17"]
 fn _msrv_118() {
-    #![clippy::msrv = "1.17"]
     let mut hash_set = HashSet::from([1, 2, 3, 4, 5, 6]);
     hash_set = hash_set.into_iter().filter(|x| x % 2 == 0).collect();
     let mut hash_map: HashMap<i8, i8> = (0..8).map(|x| (x, x * 10)).collect();
index 81a849fe7684ccbb5e3fcbf6b11ae4392391f2c2..1021f15edd1ea9c579aa8ceff38c17f12eb22414 100644 (file)
@@ -1,5 +1,4 @@
 // run-rustfix
-#![feature(custom_inner_attributes)]
 #![warn(clippy::manual_retain)]
 #![allow(unused)]
 use std::collections::BTreeMap;
@@ -222,8 +221,8 @@ fn vec_deque_retain() {
     bar = foobar.into_iter().filter(|x| x % 2 == 0).collect();
 }
 
+#[clippy::msrv = "1.52"]
 fn _msrv_153() {
-    #![clippy::msrv = "1.52"]
     let mut btree_map: BTreeMap<i8, i8> = (0..8).map(|x| (x, x * 10)).collect();
     btree_map = btree_map.into_iter().filter(|(k, _)| k % 2 == 0).collect();
 
@@ -231,14 +230,14 @@ fn _msrv_153() {
     btree_set = btree_set.iter().filter(|&x| x % 2 == 0).copied().collect();
 }
 
+#[clippy::msrv = "1.25"]
 fn _msrv_126() {
-    #![clippy::msrv = "1.25"]
     let mut s = String::from("foobar");
     s = s.chars().filter(|&c| c != 'o').to_owned().collect();
 }
 
+#[clippy::msrv = "1.17"]
 fn _msrv_118() {
-    #![clippy::msrv = "1.17"]
     let mut hash_set = HashSet::from([1, 2, 3, 4, 5, 6]);
     hash_set = hash_set.into_iter().filter(|x| x % 2 == 0).collect();
     let mut hash_map: HashMap<i8, i8> = (0..8).map(|x| (x, x * 10)).collect();
index ec635919b48fb99814c6b908d4da38d8b4ec9084..89316ce1d99818d83c236178381da84272d8d8f8 100644 (file)
@@ -1,5 +1,5 @@
 error: this expression can be written more simply using `.retain()`
-  --> $DIR/manual_retain.rs:52:5
+  --> $DIR/manual_retain.rs:51:5
    |
 LL |     btree_map = btree_map.into_iter().filter(|(k, _)| k % 2 == 0).collect();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `btree_map.retain(|k, _| k % 2 == 0)`
@@ -7,13 +7,13 @@ LL |     btree_map = btree_map.into_iter().filter(|(k, _)| k % 2 == 0).collect()
    = note: `-D clippy::manual-retain` implied by `-D warnings`
 
 error: this expression can be written more simply using `.retain()`
-  --> $DIR/manual_retain.rs:53:5
+  --> $DIR/manual_retain.rs:52:5
    |
 LL |     btree_map = btree_map.into_iter().filter(|(_, v)| v % 2 == 0).collect();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `btree_map.retain(|_, &mut v| v % 2 == 0)`
 
 error: this expression can be written more simply using `.retain()`
-  --> $DIR/manual_retain.rs:54:5
+  --> $DIR/manual_retain.rs:53:5
    |
 LL | /     btree_map = btree_map
 LL | |         .into_iter()
@@ -22,37 +22,37 @@ LL | |         .collect();
    | |__________________^ help: consider calling `.retain()` instead: `btree_map.retain(|k, &mut v| (k % 2 == 0) && (v % 2 == 0))`
 
 error: this expression can be written more simply using `.retain()`
-  --> $DIR/manual_retain.rs:76:5
+  --> $DIR/manual_retain.rs:75:5
    |
 LL |     btree_set = btree_set.iter().filter(|&x| x % 2 == 0).copied().collect();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `btree_set.retain(|x| x % 2 == 0)`
 
 error: this expression can be written more simply using `.retain()`
-  --> $DIR/manual_retain.rs:77:5
+  --> $DIR/manual_retain.rs:76:5
    |
 LL |     btree_set = btree_set.iter().filter(|&x| x % 2 == 0).cloned().collect();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `btree_set.retain(|x| x % 2 == 0)`
 
 error: this expression can be written more simply using `.retain()`
-  --> $DIR/manual_retain.rs:78:5
+  --> $DIR/manual_retain.rs:77:5
    |
 LL |     btree_set = btree_set.into_iter().filter(|x| x % 2 == 0).collect();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `btree_set.retain(|x| x % 2 == 0)`
 
 error: this expression can be written more simply using `.retain()`
-  --> $DIR/manual_retain.rs:108:5
+  --> $DIR/manual_retain.rs:107:5
    |
 LL |     hash_map = hash_map.into_iter().filter(|(k, _)| k % 2 == 0).collect();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `hash_map.retain(|k, _| k % 2 == 0)`
 
 error: this expression can be written more simply using `.retain()`
-  --> $DIR/manual_retain.rs:109:5
+  --> $DIR/manual_retain.rs:108:5
    |
 LL |     hash_map = hash_map.into_iter().filter(|(_, v)| v % 2 == 0).collect();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `hash_map.retain(|_, &mut v| v % 2 == 0)`
 
 error: this expression can be written more simply using `.retain()`
-  --> $DIR/manual_retain.rs:110:5
+  --> $DIR/manual_retain.rs:109:5
    |
 LL | /     hash_map = hash_map
 LL | |         .into_iter()
@@ -61,61 +61,61 @@ LL | |         .collect();
    | |__________________^ help: consider calling `.retain()` instead: `hash_map.retain(|k, &mut v| (k % 2 == 0) && (v % 2 == 0))`
 
 error: this expression can be written more simply using `.retain()`
-  --> $DIR/manual_retain.rs:131:5
+  --> $DIR/manual_retain.rs:130:5
    |
 LL |     hash_set = hash_set.into_iter().filter(|x| x % 2 == 0).collect();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `hash_set.retain(|x| x % 2 == 0)`
 
 error: this expression can be written more simply using `.retain()`
-  --> $DIR/manual_retain.rs:132:5
+  --> $DIR/manual_retain.rs:131:5
    |
 LL |     hash_set = hash_set.iter().filter(|&x| x % 2 == 0).copied().collect();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `hash_set.retain(|x| x % 2 == 0)`
 
 error: this expression can be written more simply using `.retain()`
-  --> $DIR/manual_retain.rs:133:5
+  --> $DIR/manual_retain.rs:132:5
    |
 LL |     hash_set = hash_set.iter().filter(|&x| x % 2 == 0).cloned().collect();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `hash_set.retain(|x| x % 2 == 0)`
 
 error: this expression can be written more simply using `.retain()`
-  --> $DIR/manual_retain.rs:162:5
+  --> $DIR/manual_retain.rs:161:5
    |
 LL |     s = s.chars().filter(|&c| c != 'o').to_owned().collect();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `s.retain(|c| c != 'o')`
 
 error: this expression can be written more simply using `.retain()`
-  --> $DIR/manual_retain.rs:174:5
+  --> $DIR/manual_retain.rs:173:5
    |
 LL |     vec = vec.iter().filter(|&x| x % 2 == 0).copied().collect();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `vec.retain(|x| x % 2 == 0)`
 
 error: this expression can be written more simply using `.retain()`
-  --> $DIR/manual_retain.rs:175:5
+  --> $DIR/manual_retain.rs:174:5
    |
 LL |     vec = vec.iter().filter(|&x| x % 2 == 0).cloned().collect();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `vec.retain(|x| x % 2 == 0)`
 
 error: this expression can be written more simply using `.retain()`
-  --> $DIR/manual_retain.rs:176:5
+  --> $DIR/manual_retain.rs:175:5
    |
 LL |     vec = vec.into_iter().filter(|x| x % 2 == 0).collect();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `vec.retain(|x| x % 2 == 0)`
 
 error: this expression can be written more simply using `.retain()`
-  --> $DIR/manual_retain.rs:198:5
+  --> $DIR/manual_retain.rs:197:5
    |
 LL |     vec_deque = vec_deque.iter().filter(|&x| x % 2 == 0).copied().collect();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `vec_deque.retain(|x| x % 2 == 0)`
 
 error: this expression can be written more simply using `.retain()`
-  --> $DIR/manual_retain.rs:199:5
+  --> $DIR/manual_retain.rs:198:5
    |
 LL |     vec_deque = vec_deque.iter().filter(|&x| x % 2 == 0).cloned().collect();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `vec_deque.retain(|x| x % 2 == 0)`
 
 error: this expression can be written more simply using `.retain()`
-  --> $DIR/manual_retain.rs:200:5
+  --> $DIR/manual_retain.rs:199:5
    |
 LL |     vec_deque = vec_deque.into_iter().filter(|x| x % 2 == 0).collect();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `vec_deque.retain(|x| x % 2 == 0)`
index c7ca770434a318c53308c073bbb72ecc3e540749..50b02019cc274f67c33d571a402c7e889f868b08 100644 (file)
@@ -1,6 +1,5 @@
 // run-rustfix
 
-#![feature(custom_inner_attributes)]
 #![warn(clippy::manual_split_once)]
 #![allow(unused, clippy::iter_skip_next, clippy::iter_nth_zero)]
 
@@ -127,8 +126,8 @@ fn indirect() -> Option<()> {
     None
 }
 
+#[clippy::msrv = "1.51"]
 fn _msrv_1_51() {
-    #![clippy::msrv = "1.51"]
     // `str::split_once` was stabilized in 1.52. Do not lint this
     let _ = "key=value".splitn(2, '=').nth(1).unwrap();
 
@@ -137,8 +136,8 @@ fn _msrv_1_51() {
     let b = iter.next().unwrap();
 }
 
+#[clippy::msrv = "1.52"]
 fn _msrv_1_52() {
-    #![clippy::msrv = "1.52"]
     let _ = "key=value".split_once('=').unwrap().1;
 
     let (a, b) = "a.b.c".split_once('.').unwrap();
index ee2848a251ee3b2e666c49644a7768597e41782d..e1e8b71a9deff62a3b716b033e777402a732d0e9 100644 (file)
@@ -1,6 +1,5 @@
 // run-rustfix
 
-#![feature(custom_inner_attributes)]
 #![warn(clippy::manual_split_once)]
 #![allow(unused, clippy::iter_skip_next, clippy::iter_nth_zero)]
 
@@ -127,8 +126,8 @@ fn indirect() -> Option<()> {
     None
 }
 
+#[clippy::msrv = "1.51"]
 fn _msrv_1_51() {
-    #![clippy::msrv = "1.51"]
     // `str::split_once` was stabilized in 1.52. Do not lint this
     let _ = "key=value".splitn(2, '=').nth(1).unwrap();
 
@@ -137,8 +136,8 @@ fn _msrv_1_51() {
     let b = iter.next().unwrap();
 }
 
+#[clippy::msrv = "1.52"]
 fn _msrv_1_52() {
-    #![clippy::msrv = "1.52"]
     let _ = "key=value".splitn(2, '=').nth(1).unwrap();
 
     let mut iter = "a.b.c".splitn(2, '.');
index 2696694680ad7abd56549743231a3b882444e28c..78da5a16cc52b69366ad355a359c6e1d587594fe 100644 (file)
@@ -1,5 +1,5 @@
 error: manual implementation of `split_once`
-  --> $DIR/manual_split_once.rs:14:13
+  --> $DIR/manual_split_once.rs:13:13
    |
 LL |     let _ = "key=value".splitn(2, '=').nth(1).unwrap();
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `"key=value".split_once('=').unwrap().1`
@@ -7,79 +7,79 @@ LL |     let _ = "key=value".splitn(2, '=').nth(1).unwrap();
    = note: `-D clippy::manual-split-once` implied by `-D warnings`
 
 error: manual implementation of `split_once`
-  --> $DIR/manual_split_once.rs:15:13
+  --> $DIR/manual_split_once.rs:14:13
    |
 LL |     let _ = "key=value".splitn(2, '=').skip(1).next().unwrap();
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `"key=value".split_once('=').unwrap().1`
 
 error: manual implementation of `split_once`
-  --> $DIR/manual_split_once.rs:16:18
+  --> $DIR/manual_split_once.rs:15:18
    |
 LL |     let (_, _) = "key=value".splitn(2, '=').next_tuple().unwrap();
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `"key=value".split_once('=')`
 
 error: manual implementation of `split_once`
-  --> $DIR/manual_split_once.rs:19:13
+  --> $DIR/manual_split_once.rs:18:13
    |
 LL |     let _ = s.splitn(2, '=').nth(1).unwrap();
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `s.split_once('=').unwrap().1`
 
 error: manual implementation of `split_once`
-  --> $DIR/manual_split_once.rs:22:13
+  --> $DIR/manual_split_once.rs:21:13
    |
 LL |     let _ = s.splitn(2, '=').nth(1).unwrap();
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `s.split_once('=').unwrap().1`
 
 error: manual implementation of `split_once`
-  --> $DIR/manual_split_once.rs:25:13
+  --> $DIR/manual_split_once.rs:24:13
    |
 LL |     let _ = s.splitn(2, '=').skip(1).next().unwrap();
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `s.split_once('=').unwrap().1`
 
 error: manual implementation of `split_once`
-  --> $DIR/manual_split_once.rs:28:17
+  --> $DIR/manual_split_once.rs:27:17
    |
 LL |         let _ = s.splitn(2, '=').nth(1)?;
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `s.split_once('=')?.1`
 
 error: manual implementation of `split_once`
-  --> $DIR/manual_split_once.rs:29:17
+  --> $DIR/manual_split_once.rs:28:17
    |
 LL |         let _ = s.splitn(2, '=').skip(1).next()?;
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `s.split_once('=')?.1`
 
 error: manual implementation of `rsplit_once`
-  --> $DIR/manual_split_once.rs:30:17
+  --> $DIR/manual_split_once.rs:29:17
    |
 LL |         let _ = s.rsplitn(2, '=').nth(1)?;
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `s.rsplit_once('=')?.0`
 
 error: manual implementation of `rsplit_once`
-  --> $DIR/manual_split_once.rs:31:17
+  --> $DIR/manual_split_once.rs:30:17
    |
 LL |         let _ = s.rsplitn(2, '=').skip(1).next()?;
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `s.rsplit_once('=')?.0`
 
 error: manual implementation of `rsplit_once`
-  --> $DIR/manual_split_once.rs:39:13
+  --> $DIR/manual_split_once.rs:38:13
    |
 LL |     let _ = "key=value".rsplitn(2, '=').nth(1).unwrap();
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `"key=value".rsplit_once('=').unwrap().0`
 
 error: manual implementation of `rsplit_once`
-  --> $DIR/manual_split_once.rs:40:18
+  --> $DIR/manual_split_once.rs:39:18
    |
 LL |     let (_, _) = "key=value".rsplitn(2, '=').next_tuple().unwrap();
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `"key=value".rsplit_once('=').map(|(x, y)| (y, x))`
 
 error: manual implementation of `rsplit_once`
-  --> $DIR/manual_split_once.rs:41:13
+  --> $DIR/manual_split_once.rs:40:13
    |
 LL |     let _ = s.rsplitn(2, '=').nth(1);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `s.rsplit_once('=').map(|x| x.0)`
 
 error: manual implementation of `split_once`
-  --> $DIR/manual_split_once.rs:45:5
+  --> $DIR/manual_split_once.rs:44:5
    |
 LL |     let mut iter = "a.b.c".splitn(2, '.');
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -104,7 +104,7 @@ LL +
    |
 
 error: manual implementation of `split_once`
-  --> $DIR/manual_split_once.rs:49:5
+  --> $DIR/manual_split_once.rs:48:5
    |
 LL |     let mut iter = "a.b.c".splitn(2, '.');
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -129,7 +129,7 @@ LL +
    |
 
 error: manual implementation of `rsplit_once`
-  --> $DIR/manual_split_once.rs:53:5
+  --> $DIR/manual_split_once.rs:52:5
    |
 LL |     let mut iter = "a.b.c".rsplitn(2, '.');
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -154,7 +154,7 @@ LL +
    |
 
 error: manual implementation of `rsplit_once`
-  --> $DIR/manual_split_once.rs:57:5
+  --> $DIR/manual_split_once.rs:56:5
    |
 LL |     let mut iter = "a.b.c".rsplitn(2, '.');
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -179,13 +179,13 @@ LL +
    |
 
 error: manual implementation of `split_once`
-  --> $DIR/manual_split_once.rs:142:13
+  --> $DIR/manual_split_once.rs:141:13
    |
 LL |     let _ = "key=value".splitn(2, '=').nth(1).unwrap();
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `"key=value".split_once('=').unwrap().1`
 
 error: manual implementation of `split_once`
-  --> $DIR/manual_split_once.rs:144:5
+  --> $DIR/manual_split_once.rs:143:5
    |
 LL |     let mut iter = "a.b.c".splitn(2, '.');
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
index 0704ba2f933eb774dd91fedab659bec8ae1e1fcb..3d56f2a0dedb2deefbc3676374964f9bd3d3bb1d 100644 (file)
@@ -1,6 +1,5 @@
 // run-rustfix
 
-#![feature(custom_inner_attributes)]
 #![warn(clippy::manual_str_repeat)]
 
 use std::borrow::Cow;
@@ -54,13 +53,13 @@ fn main() {
     let _: String = repeat(x).take(count).collect();
 }
 
+#[clippy::msrv = "1.15"]
 fn _msrv_1_15() {
-    #![clippy::msrv = "1.15"]
     // `str::repeat` was stabilized in 1.16. Do not lint this
     let _: String = std::iter::repeat("test").take(10).collect();
 }
 
+#[clippy::msrv = "1.16"]
 fn _msrv_1_16() {
-    #![clippy::msrv = "1.16"]
     let _: String = "test".repeat(10);
 }
index f522be439aa0eaf0a69f5217c88c1ead4d67eee8..e8240a949dbc248c4b2ad11dd2a67a42204a01d7 100644 (file)
@@ -1,6 +1,5 @@
 // run-rustfix
 
-#![feature(custom_inner_attributes)]
 #![warn(clippy::manual_str_repeat)]
 
 use std::borrow::Cow;
@@ -54,13 +53,13 @@ fn from_iter<T: IntoIterator<Item = Box<S>>>(_: T) -> Self {
     let _: String = repeat(x).take(count).collect();
 }
 
+#[clippy::msrv = "1.15"]
 fn _msrv_1_15() {
-    #![clippy::msrv = "1.15"]
     // `str::repeat` was stabilized in 1.16. Do not lint this
     let _: String = std::iter::repeat("test").take(10).collect();
 }
 
+#[clippy::msrv = "1.16"]
 fn _msrv_1_16() {
-    #![clippy::msrv = "1.16"]
     let _: String = std::iter::repeat("test").take(10).collect();
 }
index c65116897164409e7b4ecb3862bfce925418b6c9..bdfee7cab261e197ce9abce874836ba234448b23 100644 (file)
@@ -1,5 +1,5 @@
 error: manual implementation of `str::repeat` using iterators
-  --> $DIR/manual_str_repeat.rs:10:21
+  --> $DIR/manual_str_repeat.rs:9:21
    |
 LL |     let _: String = std::iter::repeat("test").take(10).collect();
    |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `"test".repeat(10)`
@@ -7,55 +7,55 @@ LL |     let _: String = std::iter::repeat("test").take(10).collect();
    = note: `-D clippy::manual-str-repeat` implied by `-D warnings`
 
 error: manual implementation of `str::repeat` using iterators
-  --> $DIR/manual_str_repeat.rs:11:21
+  --> $DIR/manual_str_repeat.rs:10:21
    |
 LL |     let _: String = std::iter::repeat('x').take(10).collect();
    |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `"x".repeat(10)`
 
 error: manual implementation of `str::repeat` using iterators
-  --> $DIR/manual_str_repeat.rs:12:21
+  --> $DIR/manual_str_repeat.rs:11:21
    |
 LL |     let _: String = std::iter::repeat('/'').take(10).collect();
    |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `"'".repeat(10)`
 
 error: manual implementation of `str::repeat` using iterators
-  --> $DIR/manual_str_repeat.rs:13:21
+  --> $DIR/manual_str_repeat.rs:12:21
    |
 LL |     let _: String = std::iter::repeat('"').take(10).collect();
    |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `"/"".repeat(10)`
 
 error: manual implementation of `str::repeat` using iterators
-  --> $DIR/manual_str_repeat.rs:17:13
+  --> $DIR/manual_str_repeat.rs:16:13
    |
 LL |     let _ = repeat(x).take(count + 2).collect::<String>();
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `x.repeat(count + 2)`
 
 error: manual implementation of `str::repeat` using iterators
-  --> $DIR/manual_str_repeat.rs:26:21
+  --> $DIR/manual_str_repeat.rs:25:21
    |
 LL |     let _: String = repeat(*x).take(count).collect();
    |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `(*x).repeat(count)`
 
 error: manual implementation of `str::repeat` using iterators
-  --> $DIR/manual_str_repeat.rs:35:21
+  --> $DIR/manual_str_repeat.rs:34:21
    |
 LL |     let _: String = repeat(x).take(count).collect();
    |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `x.repeat(count)`
 
 error: manual implementation of `str::repeat` using iterators
-  --> $DIR/manual_str_repeat.rs:47:21
+  --> $DIR/manual_str_repeat.rs:46:21
    |
 LL |     let _: String = repeat(Cow::Borrowed("test")).take(count).collect();
    |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `Cow::Borrowed("test").repeat(count)`
 
 error: manual implementation of `str::repeat` using iterators
-  --> $DIR/manual_str_repeat.rs:50:21
+  --> $DIR/manual_str_repeat.rs:49:21
    |
 LL |     let _: String = repeat(x).take(count).collect();
    |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `x.repeat(count)`
 
 error: manual implementation of `str::repeat` using iterators
-  --> $DIR/manual_str_repeat.rs:65:21
+  --> $DIR/manual_str_repeat.rs:64:21
    |
 LL |     let _: String = std::iter::repeat("test").take(10).collect();
    |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `"test".repeat(10)`
index 85009d78558ba7d68abd82b3b76680fad600adf7..b0b1c262aeed846f9bb6e105014cf575d4eaa5eb 100644 (file)
@@ -1,4 +1,3 @@
-#![feature(custom_inner_attributes)]
 #![warn(clippy::manual_strip)]
 
 fn main() {
@@ -66,18 +65,16 @@ fn main() {
     }
 }
 
+#[clippy::msrv = "1.44"]
 fn msrv_1_44() {
-    #![clippy::msrv = "1.44"]
-
     let s = "abc";
     if s.starts_with('a') {
         s[1..].to_string();
     }
 }
 
+#[clippy::msrv = "1.45"]
 fn msrv_1_45() {
-    #![clippy::msrv = "1.45"]
-
     let s = "abc";
     if s.starts_with('a') {
         s[1..].to_string();
index ad2a362f3e76ddb2d3d404952da30db254f8288b..f592e898fc928d7e7d8b8c05f263cd6e8af401b3 100644 (file)
@@ -1,11 +1,11 @@
 error: stripping a prefix manually
-  --> $DIR/manual_strip.rs:8:24
+  --> $DIR/manual_strip.rs:7:24
    |
 LL |         str::to_string(&s["ab".len()..]);
    |                        ^^^^^^^^^^^^^^^^
    |
 note: the prefix was tested here
-  --> $DIR/manual_strip.rs:7:5
+  --> $DIR/manual_strip.rs:6:5
    |
 LL |     if s.starts_with("ab") {
    |     ^^^^^^^^^^^^^^^^^^^^^^^
@@ -21,13 +21,13 @@ LL ~         <stripped>.to_string();
    |
 
 error: stripping a suffix manually
-  --> $DIR/manual_strip.rs:16:24
+  --> $DIR/manual_strip.rs:15:24
    |
 LL |         str::to_string(&s[..s.len() - "bc".len()]);
    |                        ^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 note: the suffix was tested here
-  --> $DIR/manual_strip.rs:15:5
+  --> $DIR/manual_strip.rs:14:5
    |
 LL |     if s.ends_with("bc") {
    |     ^^^^^^^^^^^^^^^^^^^^^
@@ -42,13 +42,13 @@ LL ~         <stripped>.to_string();
    |
 
 error: stripping a prefix manually
-  --> $DIR/manual_strip.rs:25:24
+  --> $DIR/manual_strip.rs:24:24
    |
 LL |         str::to_string(&s[1..]);
    |                        ^^^^^^^
    |
 note: the prefix was tested here
-  --> $DIR/manual_strip.rs:24:5
+  --> $DIR/manual_strip.rs:23:5
    |
 LL |     if s.starts_with('a') {
    |     ^^^^^^^^^^^^^^^^^^^^^^
@@ -60,13 +60,13 @@ LL ~         <stripped>.to_string();
    |
 
 error: stripping a prefix manually
-  --> $DIR/manual_strip.rs:32:24
+  --> $DIR/manual_strip.rs:31:24
    |
 LL |         str::to_string(&s[prefix.len()..]);
    |                        ^^^^^^^^^^^^^^^^^^
    |
 note: the prefix was tested here
-  --> $DIR/manual_strip.rs:31:5
+  --> $DIR/manual_strip.rs:30:5
    |
 LL |     if s.starts_with(prefix) {
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -77,13 +77,13 @@ LL ~         str::to_string(<stripped>);
    |
 
 error: stripping a prefix manually
-  --> $DIR/manual_strip.rs:38:24
+  --> $DIR/manual_strip.rs:37:24
    |
 LL |         str::to_string(&s[PREFIX.len()..]);
    |                        ^^^^^^^^^^^^^^^^^^
    |
 note: the prefix was tested here
-  --> $DIR/manual_strip.rs:37:5
+  --> $DIR/manual_strip.rs:36:5
    |
 LL |     if s.starts_with(PREFIX) {
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -95,13 +95,13 @@ LL ~         str::to_string(<stripped>);
    |
 
 error: stripping a prefix manually
-  --> $DIR/manual_strip.rs:45:24
+  --> $DIR/manual_strip.rs:44:24
    |
 LL |         str::to_string(&TARGET[prefix.len()..]);
    |                        ^^^^^^^^^^^^^^^^^^^^^^^
    |
 note: the prefix was tested here
-  --> $DIR/manual_strip.rs:44:5
+  --> $DIR/manual_strip.rs:43:5
    |
 LL |     if TARGET.starts_with(prefix) {
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -112,13 +112,13 @@ LL ~         str::to_string(<stripped>);
    |
 
 error: stripping a prefix manually
-  --> $DIR/manual_strip.rs:51:9
+  --> $DIR/manual_strip.rs:50:9
    |
 LL |         s1[2..].to_uppercase();
    |         ^^^^^^^
    |
 note: the prefix was tested here
-  --> $DIR/manual_strip.rs:50:5
+  --> $DIR/manual_strip.rs:49:5
    |
 LL |     if s1.starts_with("ab") {
    |     ^^^^^^^^^^^^^^^^^^^^^^^^
@@ -129,13 +129,13 @@ LL ~         <stripped>.to_uppercase();
    |
 
 error: stripping a prefix manually
-  --> $DIR/manual_strip.rs:83:9
+  --> $DIR/manual_strip.rs:80:9
    |
 LL |         s[1..].to_string();
    |         ^^^^^^
    |
 note: the prefix was tested here
-  --> $DIR/manual_strip.rs:82:5
+  --> $DIR/manual_strip.rs:79:5
    |
 LL |     if s.starts_with('a') {
    |     ^^^^^^^^^^^^^^^^^^^^^^
index 396b22a9abb390f520d911a773d688b8bb2f3992..32631024ca5dca840d75fecb7487f7aceca29642 100644 (file)
@@ -1,6 +1,5 @@
 // aux-build:option_helpers.rs
 
-#![feature(custom_inner_attributes)]
 #![warn(clippy::map_unwrap_or)]
 #![allow(clippy::uninlined_format_args, clippy::unnecessary_lazy_evaluations)]
 
@@ -82,17 +81,15 @@ fn main() {
     result_methods();
 }
 
+#[clippy::msrv = "1.40"]
 fn msrv_1_40() {
-    #![clippy::msrv = "1.40"]
-
     let res: Result<i32, ()> = Ok(1);
 
     let _ = res.map(|x| x + 1).unwrap_or_else(|_e| 0);
 }
 
+#[clippy::msrv = "1.41"]
 fn msrv_1_41() {
-    #![clippy::msrv = "1.41"]
-
     let res: Result<i32, ()> = Ok(1);
 
     let _ = res.map(|x| x + 1).unwrap_or_else(|_e| 0);
index d17d24a403ea5d578c01d51f725559553f2d75ee..41781b050fa20a5df494c0625c2c73608d8d42d8 100644 (file)
@@ -1,5 +1,5 @@
 error: called `map(<f>).unwrap_or(<a>)` on an `Option` value. This can be done more directly by calling `map_or(<a>, <f>)` instead
-  --> $DIR/map_unwrap_or.rs:18:13
+  --> $DIR/map_unwrap_or.rs:17:13
    |
 LL |       let _ = opt.map(|x| x + 1)
    |  _____________^
@@ -15,7 +15,7 @@ LL +     let _ = opt.map_or(0, |x| x + 1);
    |
 
 error: called `map(<f>).unwrap_or(<a>)` on an `Option` value. This can be done more directly by calling `map_or(<a>, <f>)` instead
-  --> $DIR/map_unwrap_or.rs:22:13
+  --> $DIR/map_unwrap_or.rs:21:13
    |
 LL |       let _ = opt.map(|x| {
    |  _____________^
@@ -33,7 +33,7 @@ LL ~     );
    |
 
 error: called `map(<f>).unwrap_or(<a>)` on an `Option` value. This can be done more directly by calling `map_or(<a>, <f>)` instead
-  --> $DIR/map_unwrap_or.rs:26:13
+  --> $DIR/map_unwrap_or.rs:25:13
    |
 LL |       let _ = opt.map(|x| x + 1)
    |  _____________^
@@ -50,7 +50,7 @@ LL ~         }, |x| x + 1);
    |
 
 error: called `map(<f>).unwrap_or(None)` on an `Option` value. This can be done more directly by calling `and_then(<f>)` instead
-  --> $DIR/map_unwrap_or.rs:31:13
+  --> $DIR/map_unwrap_or.rs:30:13
    |
 LL |     let _ = opt.map(|x| Some(x + 1)).unwrap_or(None);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -62,7 +62,7 @@ LL +     let _ = opt.and_then(|x| Some(x + 1));
    |
 
 error: called `map(<f>).unwrap_or(None)` on an `Option` value. This can be done more directly by calling `and_then(<f>)` instead
-  --> $DIR/map_unwrap_or.rs:33:13
+  --> $DIR/map_unwrap_or.rs:32:13
    |
 LL |       let _ = opt.map(|x| {
    |  _____________^
@@ -80,7 +80,7 @@ LL ~     );
    |
 
 error: called `map(<f>).unwrap_or(None)` on an `Option` value. This can be done more directly by calling `and_then(<f>)` instead
-  --> $DIR/map_unwrap_or.rs:37:13
+  --> $DIR/map_unwrap_or.rs:36:13
    |
 LL |       let _ = opt
    |  _____________^
@@ -95,7 +95,7 @@ LL +         .and_then(|x| Some(x + 1));
    |
 
 error: called `map(<f>).unwrap_or(<a>)` on an `Option` value. This can be done more directly by calling `map_or(<a>, <f>)` instead
-  --> $DIR/map_unwrap_or.rs:48:13
+  --> $DIR/map_unwrap_or.rs:47:13
    |
 LL |     let _ = Some("prefix").map(|p| format!("{}.", p)).unwrap_or(id);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -107,7 +107,7 @@ LL +     let _ = Some("prefix").map_or(id, |p| format!("{}.", p));
    |
 
 error: called `map(<f>).unwrap_or_else(<g>)` on an `Option` value. This can be done more directly by calling `map_or_else(<g>, <f>)` instead
-  --> $DIR/map_unwrap_or.rs:52:13
+  --> $DIR/map_unwrap_or.rs:51:13
    |
 LL |       let _ = opt.map(|x| {
    |  _____________^
@@ -117,7 +117,7 @@ LL | |     ).unwrap_or_else(|| 0);
    | |__________________________^
 
 error: called `map(<f>).unwrap_or_else(<g>)` on an `Option` value. This can be done more directly by calling `map_or_else(<g>, <f>)` instead
-  --> $DIR/map_unwrap_or.rs:56:13
+  --> $DIR/map_unwrap_or.rs:55:13
    |
 LL |       let _ = opt.map(|x| x + 1)
    |  _____________^
@@ -127,7 +127,7 @@ LL | |         );
    | |_________^
 
 error: called `map(<f>).unwrap_or_else(<g>)` on a `Result` value. This can be done more directly by calling `.map_or_else(<g>, <f>)` instead
-  --> $DIR/map_unwrap_or.rs:68:13
+  --> $DIR/map_unwrap_or.rs:67:13
    |
 LL |       let _ = res.map(|x| {
    |  _____________^
@@ -137,7 +137,7 @@ LL | |     ).unwrap_or_else(|_e| 0);
    | |____________________________^
 
 error: called `map(<f>).unwrap_or_else(<g>)` on a `Result` value. This can be done more directly by calling `.map_or_else(<g>, <f>)` instead
-  --> $DIR/map_unwrap_or.rs:72:13
+  --> $DIR/map_unwrap_or.rs:71:13
    |
 LL |       let _ = res.map(|x| x + 1)
    |  _____________^
@@ -147,7 +147,7 @@ LL | |         });
    | |__________^
 
 error: called `map(<f>).unwrap_or_else(<g>)` on a `Result` value. This can be done more directly by calling `.map_or_else(<g>, <f>)` instead
-  --> $DIR/map_unwrap_or.rs:98:13
+  --> $DIR/map_unwrap_or.rs:95:13
    |
 LL |     let _ = res.map(|x| x + 1).unwrap_or_else(|_e| 0);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `res.map_or_else(|_e| 0, |x| x + 1)`
index 968f462f8a029d19f2d5dfae483dcc976d403496..55cd15bd5c3858adb81df923ac8830385a5b5c48 100644 (file)
@@ -1,6 +1,5 @@
 // run-rustfix
 
-#![feature(custom_inner_attributes)]
 #![warn(clippy::match_like_matches_macro)]
 #![allow(
     unreachable_patterns,
@@ -200,17 +199,15 @@ fn main() {
     };
 }
 
+#[clippy::msrv = "1.41"]
 fn msrv_1_41() {
-    #![clippy::msrv = "1.41"]
-
     let _y = match Some(5) {
         Some(0) => true,
         _ => false,
     };
 }
 
+#[clippy::msrv = "1.42"]
 fn msrv_1_42() {
-    #![clippy::msrv = "1.42"]
-
     let _y = matches!(Some(5), Some(0));
 }
index c6b479e27c5aca477a73e782291f7663412669bb..5d645e108e511859e73013037be76ffcd786e59b 100644 (file)
@@ -1,6 +1,5 @@
 // run-rustfix
 
-#![feature(custom_inner_attributes)]
 #![warn(clippy::match_like_matches_macro)]
 #![allow(
     unreachable_patterns,
@@ -241,18 +240,16 @@ enum E {
     };
 }
 
+#[clippy::msrv = "1.41"]
 fn msrv_1_41() {
-    #![clippy::msrv = "1.41"]
-
     let _y = match Some(5) {
         Some(0) => true,
         _ => false,
     };
 }
 
+#[clippy::msrv = "1.42"]
 fn msrv_1_42() {
-    #![clippy::msrv = "1.42"]
-
     let _y = match Some(5) {
         Some(0) => true,
         _ => false,
index a4df8008ac239288436dc9919382b7f2304e58d6..46f67ef4900f8d6d001ccd47e07748801013bfa8 100644 (file)
@@ -1,5 +1,5 @@
 error: match expression looks like `matches!` macro
-  --> $DIR/match_expr_like_matches_macro.rs:16:14
+  --> $DIR/match_expr_like_matches_macro.rs:15:14
    |
 LL |       let _y = match x {
    |  ______________^
@@ -11,7 +11,7 @@ LL | |     };
    = note: `-D clippy::match-like-matches-macro` implied by `-D warnings`
 
 error: match expression looks like `matches!` macro
-  --> $DIR/match_expr_like_matches_macro.rs:22:14
+  --> $DIR/match_expr_like_matches_macro.rs:21:14
    |
 LL |       let _w = match x {
    |  ______________^
@@ -21,7 +21,7 @@ LL | |     };
    | |_____^ help: try this: `matches!(x, Some(_))`
 
 error: redundant pattern matching, consider using `is_none()`
-  --> $DIR/match_expr_like_matches_macro.rs:28:14
+  --> $DIR/match_expr_like_matches_macro.rs:27:14
    |
 LL |       let _z = match x {
    |  ______________^
@@ -33,7 +33,7 @@ LL | |     };
    = note: `-D clippy::redundant-pattern-matching` implied by `-D warnings`
 
 error: match expression looks like `matches!` macro
-  --> $DIR/match_expr_like_matches_macro.rs:34:15
+  --> $DIR/match_expr_like_matches_macro.rs:33:15
    |
 LL |       let _zz = match x {
    |  _______________^
@@ -43,13 +43,13 @@ LL | |     };
    | |_____^ help: try this: `!matches!(x, Some(r) if r == 0)`
 
 error: if let .. else expression looks like `matches!` macro
-  --> $DIR/match_expr_like_matches_macro.rs:40:16
+  --> $DIR/match_expr_like_matches_macro.rs:39:16
    |
 LL |     let _zzz = if let Some(5) = x { true } else { false };
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `matches!(x, Some(5))`
 
 error: match expression looks like `matches!` macro
-  --> $DIR/match_expr_like_matches_macro.rs:64:20
+  --> $DIR/match_expr_like_matches_macro.rs:63:20
    |
 LL |           let _ans = match x {
    |  ____________________^
@@ -60,7 +60,7 @@ LL | |         };
    | |_________^ help: try this: `matches!(x, E::A(_) | E::B(_))`
 
 error: match expression looks like `matches!` macro
-  --> $DIR/match_expr_like_matches_macro.rs:74:20
+  --> $DIR/match_expr_like_matches_macro.rs:73:20
    |
 LL |           let _ans = match x {
    |  ____________________^
@@ -73,7 +73,7 @@ LL | |         };
    | |_________^ help: try this: `matches!(x, E::A(_) | E::B(_))`
 
 error: match expression looks like `matches!` macro
-  --> $DIR/match_expr_like_matches_macro.rs:84:20
+  --> $DIR/match_expr_like_matches_macro.rs:83:20
    |
 LL |           let _ans = match x {
    |  ____________________^
@@ -84,7 +84,7 @@ LL | |         };
    | |_________^ help: try this: `!matches!(x, E::B(_) | E::C)`
 
 error: match expression looks like `matches!` macro
-  --> $DIR/match_expr_like_matches_macro.rs:144:18
+  --> $DIR/match_expr_like_matches_macro.rs:143:18
    |
 LL |           let _z = match &z {
    |  __________________^
@@ -94,7 +94,7 @@ LL | |         };
    | |_________^ help: try this: `matches!(z, Some(3))`
 
 error: match expression looks like `matches!` macro
-  --> $DIR/match_expr_like_matches_macro.rs:153:18
+  --> $DIR/match_expr_like_matches_macro.rs:152:18
    |
 LL |           let _z = match &z {
    |  __________________^
@@ -104,7 +104,7 @@ LL | |         };
    | |_________^ help: try this: `matches!(&z, Some(3))`
 
 error: match expression looks like `matches!` macro
-  --> $DIR/match_expr_like_matches_macro.rs:170:21
+  --> $DIR/match_expr_like_matches_macro.rs:169:21
    |
 LL |               let _ = match &z {
    |  _____________________^
@@ -114,7 +114,7 @@ LL | |             };
    | |_____________^ help: try this: `matches!(&z, AnEnum::X)`
 
 error: match expression looks like `matches!` macro
-  --> $DIR/match_expr_like_matches_macro.rs:184:20
+  --> $DIR/match_expr_like_matches_macro.rs:183:20
    |
 LL |           let _res = match &val {
    |  ____________________^
@@ -124,7 +124,7 @@ LL | |         };
    | |_________^ help: try this: `matches!(&val, &Some(ref _a))`
 
 error: match expression looks like `matches!` macro
-  --> $DIR/match_expr_like_matches_macro.rs:196:20
+  --> $DIR/match_expr_like_matches_macro.rs:195:20
    |
 LL |           let _res = match &val {
    |  ____________________^
@@ -134,7 +134,7 @@ LL | |         };
    | |_________^ help: try this: `matches!(&val, &Some(ref _a))`
 
 error: match expression looks like `matches!` macro
-  --> $DIR/match_expr_like_matches_macro.rs:256:14
+  --> $DIR/match_expr_like_matches_macro.rs:253:14
    |
 LL |       let _y = match Some(5) {
    |  ______________^
index ae237395b95fc06d5db17bbc417a9d3c345c1974..874d558433034d217e246dd8fcf38e17f842b4bb 100644 (file)
@@ -1,6 +1,5 @@
 // run-rustfix
 
-#![feature(custom_inner_attributes)]
 #![allow(unused)]
 #![warn(
     clippy::all,
@@ -80,16 +79,14 @@ fn main() {
     dont_lint_primitive();
 }
 
+#[clippy::msrv = "1.39"]
 fn msrv_1_39() {
-    #![clippy::msrv = "1.39"]
-
     let mut s = String::from("foo");
     let _ = std::mem::replace(&mut s, String::default());
 }
 
+#[clippy::msrv = "1.40"]
 fn msrv_1_40() {
-    #![clippy::msrv = "1.40"]
-
     let mut s = String::from("foo");
     let _ = std::mem::take(&mut s);
 }
index 3202e99e0be9e99cd0957041eced7010b551fa6e..f4f3bff514463e4a04a661ab372d36579e59ec0b 100644 (file)
@@ -1,6 +1,5 @@
 // run-rustfix
 
-#![feature(custom_inner_attributes)]
 #![allow(unused)]
 #![warn(
     clippy::all,
@@ -80,16 +79,14 @@ fn main() {
     dont_lint_primitive();
 }
 
+#[clippy::msrv = "1.39"]
 fn msrv_1_39() {
-    #![clippy::msrv = "1.39"]
-
     let mut s = String::from("foo");
     let _ = std::mem::replace(&mut s, String::default());
 }
 
+#[clippy::msrv = "1.40"]
 fn msrv_1_40() {
-    #![clippy::msrv = "1.40"]
-
     let mut s = String::from("foo");
     let _ = std::mem::replace(&mut s, String::default());
 }
index dd8a50dab9002f1649d970a1af348d99993bbb0f..caa127f76eeffa8a1d92b0b75437807eb2d8bac0 100644 (file)
@@ -1,5 +1,5 @@
 error: replacing an `Option` with `None`
-  --> $DIR/mem_replace.rs:17:13
+  --> $DIR/mem_replace.rs:16:13
    |
 LL |     let _ = mem::replace(&mut an_option, None);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider `Option::take()` instead: `an_option.take()`
@@ -7,13 +7,13 @@ LL |     let _ = mem::replace(&mut an_option, None);
    = note: `-D clippy::mem-replace-option-with-none` implied by `-D warnings`
 
 error: replacing an `Option` with `None`
-  --> $DIR/mem_replace.rs:19:13
+  --> $DIR/mem_replace.rs:18:13
    |
 LL |     let _ = mem::replace(an_option, None);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider `Option::take()` instead: `an_option.take()`
 
 error: replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take`
-  --> $DIR/mem_replace.rs:24:13
+  --> $DIR/mem_replace.rs:23:13
    |
 LL |     let _ = std::mem::replace(&mut s, String::default());
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::mem::take(&mut s)`
@@ -21,103 +21,103 @@ LL |     let _ = std::mem::replace(&mut s, String::default());
    = note: `-D clippy::mem-replace-with-default` implied by `-D warnings`
 
 error: replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take`
-  --> $DIR/mem_replace.rs:27:13
+  --> $DIR/mem_replace.rs:26:13
    |
 LL |     let _ = std::mem::replace(s, String::default());
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::mem::take(s)`
 
 error: replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take`
-  --> $DIR/mem_replace.rs:28:13
+  --> $DIR/mem_replace.rs:27:13
    |
 LL |     let _ = std::mem::replace(s, Default::default());
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::mem::take(s)`
 
 error: replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take`
-  --> $DIR/mem_replace.rs:31:13
+  --> $DIR/mem_replace.rs:30:13
    |
 LL |     let _ = std::mem::replace(&mut v, Vec::default());
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::mem::take(&mut v)`
 
 error: replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take`
-  --> $DIR/mem_replace.rs:32:13
+  --> $DIR/mem_replace.rs:31:13
    |
 LL |     let _ = std::mem::replace(&mut v, Default::default());
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::mem::take(&mut v)`
 
 error: replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take`
-  --> $DIR/mem_replace.rs:33:13
+  --> $DIR/mem_replace.rs:32:13
    |
 LL |     let _ = std::mem::replace(&mut v, Vec::new());
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::mem::take(&mut v)`
 
 error: replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take`
-  --> $DIR/mem_replace.rs:34:13
+  --> $DIR/mem_replace.rs:33:13
    |
 LL |     let _ = std::mem::replace(&mut v, vec![]);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::mem::take(&mut v)`
 
 error: replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take`
-  --> $DIR/mem_replace.rs:37:13
+  --> $DIR/mem_replace.rs:36:13
    |
 LL |     let _ = std::mem::replace(&mut hash_map, HashMap::new());
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::mem::take(&mut hash_map)`
 
 error: replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take`
-  --> $DIR/mem_replace.rs:40:13
+  --> $DIR/mem_replace.rs:39:13
    |
 LL |     let _ = std::mem::replace(&mut btree_map, BTreeMap::new());
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::mem::take(&mut btree_map)`
 
 error: replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take`
-  --> $DIR/mem_replace.rs:43:13
+  --> $DIR/mem_replace.rs:42:13
    |
 LL |     let _ = std::mem::replace(&mut vd, VecDeque::new());
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::mem::take(&mut vd)`
 
 error: replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take`
-  --> $DIR/mem_replace.rs:46:13
+  --> $DIR/mem_replace.rs:45:13
    |
 LL |     let _ = std::mem::replace(&mut hash_set, HashSet::new());
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::mem::take(&mut hash_set)`
 
 error: replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take`
-  --> $DIR/mem_replace.rs:49:13
+  --> $DIR/mem_replace.rs:48:13
    |
 LL |     let _ = std::mem::replace(&mut btree_set, BTreeSet::new());
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::mem::take(&mut btree_set)`
 
 error: replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take`
-  --> $DIR/mem_replace.rs:52:13
+  --> $DIR/mem_replace.rs:51:13
    |
 LL |     let _ = std::mem::replace(&mut list, LinkedList::new());
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::mem::take(&mut list)`
 
 error: replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take`
-  --> $DIR/mem_replace.rs:55:13
+  --> $DIR/mem_replace.rs:54:13
    |
 LL |     let _ = std::mem::replace(&mut binary_heap, BinaryHeap::new());
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::mem::take(&mut binary_heap)`
 
 error: replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take`
-  --> $DIR/mem_replace.rs:58:13
+  --> $DIR/mem_replace.rs:57:13
    |
 LL |     let _ = std::mem::replace(&mut tuple, (vec![], BinaryHeap::new()));
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::mem::take(&mut tuple)`
 
 error: replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take`
-  --> $DIR/mem_replace.rs:61:13
+  --> $DIR/mem_replace.rs:60:13
    |
 LL |     let _ = std::mem::replace(&mut refstr, "");
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::mem::take(&mut refstr)`
 
 error: replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take`
-  --> $DIR/mem_replace.rs:64:13
+  --> $DIR/mem_replace.rs:63:13
    |
 LL |     let _ = std::mem::replace(&mut slice, &[]);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::mem::take(&mut slice)`
 
 error: replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take`
-  --> $DIR/mem_replace.rs:94:13
+  --> $DIR/mem_replace.rs:91:13
    |
 LL |     let _ = std::mem::replace(&mut s, String::default());
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::mem::take(&mut s)`
index cd148063bf065c304ff683fe19998885a56a3a70..955e7eb727634134ddd9df2c9ef39c8b6692e9a4 100644 (file)
@@ -3,27 +3,60 @@
 
 fn main() {}
 
+#[clippy::msrv = "1.42.0"]
 fn just_under_msrv() {
-    #![clippy::msrv = "1.42.0"]
     let log2_10 = 3.321928094887362;
 }
 
+#[clippy::msrv = "1.43.0"]
 fn meets_msrv() {
-    #![clippy::msrv = "1.43.0"]
     let log2_10 = 3.321928094887362;
 }
 
+#[clippy::msrv = "1.44.0"]
 fn just_above_msrv() {
-    #![clippy::msrv = "1.44.0"]
     let log2_10 = 3.321928094887362;
 }
 
+#[clippy::msrv = "1.42"]
 fn no_patch_under() {
-    #![clippy::msrv = "1.42"]
     let log2_10 = 3.321928094887362;
 }
 
+#[clippy::msrv = "1.43"]
 fn no_patch_meets() {
+    let log2_10 = 3.321928094887362;
+}
+
+fn inner_attr_under() {
+    #![clippy::msrv = "1.42"]
+    let log2_10 = 3.321928094887362;
+}
+
+fn inner_attr_meets() {
     #![clippy::msrv = "1.43"]
     let log2_10 = 3.321928094887362;
 }
+
+// https://github.com/rust-lang/rust-clippy/issues/6920
+fn scoping() {
+    mod m {
+        #![clippy::msrv = "1.42.0"]
+    }
+
+    // Should warn
+    let log2_10 = 3.321928094887362;
+
+    mod a {
+        #![clippy::msrv = "1.42.0"]
+
+        fn should_warn() {
+            #![clippy::msrv = "1.43.0"]
+            let log2_10 = 3.321928094887362;
+        }
+
+        fn should_not_warn() {
+            let log2_10 = 3.321928094887362;
+        }
+    }
+}
index 68aa58748190be3552ef5ad7455f95b32dc7fce8..7e2135584efde60aa144b334f15ed722860406b0 100644 (file)
@@ -23,5 +23,29 @@ LL |     let log2_10 = 3.321928094887362;
    |
    = help: consider using the constant directly
 
-error: aborting due to 3 previous errors
+error: approximate value of `f{32, 64}::consts::LOG2_10` found
+  --> $DIR/min_rust_version_attr.rs:38:19
+   |
+LL |     let log2_10 = 3.321928094887362;
+   |                   ^^^^^^^^^^^^^^^^^
+   |
+   = help: consider using the constant directly
+
+error: approximate value of `f{32, 64}::consts::LOG2_10` found
+  --> $DIR/min_rust_version_attr.rs:48:19
+   |
+LL |     let log2_10 = 3.321928094887362;
+   |                   ^^^^^^^^^^^^^^^^^
+   |
+   = help: consider using the constant directly
+
+error: approximate value of `f{32, 64}::consts::LOG2_10` found
+  --> $DIR/min_rust_version_attr.rs:55:27
+   |
+LL |             let log2_10 = 3.321928094887362;
+   |                           ^^^^^^^^^^^^^^^^^
+   |
+   = help: consider using the constant directly
+
+error: aborting due to 6 previous errors
 
index 93370a0fa9c912ce45cf972743c38714c5bcaff7..675b780315251ce20f64f17b62a4ff9c1075172c 100644 (file)
@@ -4,7 +4,7 @@ error: `invalid.version` is not a valid Rust version
 LL | #![clippy::msrv = "invalid.version"]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: `msrv` cannot be an outer attribute
+error: `invalid.version` is not a valid Rust version
   --> $DIR/min_rust_version_invalid_attr.rs:6:1
    |
 LL | #[clippy::msrv = "invalid.version"]
diff --git a/src/tools/clippy/tests/ui/misnamed_getters.rs b/src/tools/clippy/tests/ui/misnamed_getters.rs
new file mode 100644 (file)
index 0000000..03e7dac
--- /dev/null
@@ -0,0 +1,124 @@
+#![allow(unused)]
+#![warn(clippy::misnamed_getters)]
+
+struct A {
+    a: u8,
+    b: u8,
+    c: u8,
+}
+
+impl A {
+    fn a(&self) -> &u8 {
+        &self.b
+    }
+    fn a_mut(&mut self) -> &mut u8 {
+        &mut self.b
+    }
+
+    fn b(self) -> u8 {
+        self.a
+    }
+
+    fn b_mut(&mut self) -> &mut u8 {
+        &mut self.a
+    }
+
+    fn c(&self) -> &u8 {
+        &self.b
+    }
+
+    fn c_mut(&mut self) -> &mut u8 {
+        &mut self.a
+    }
+}
+
+union B {
+    a: u8,
+    b: u8,
+}
+
+impl B {
+    unsafe fn a(&self) -> &u8 {
+        &self.b
+    }
+    unsafe fn a_mut(&mut self) -> &mut u8 {
+        &mut self.b
+    }
+
+    unsafe fn b(self) -> u8 {
+        self.a
+    }
+
+    unsafe fn b_mut(&mut self) -> &mut u8 {
+        &mut self.a
+    }
+
+    unsafe fn c(&self) -> &u8 {
+        &self.b
+    }
+
+    unsafe fn c_mut(&mut self) -> &mut u8 {
+        &mut self.a
+    }
+
+    unsafe fn a_unchecked(&self) -> &u8 {
+        &self.b
+    }
+    unsafe fn a_unchecked_mut(&mut self) -> &mut u8 {
+        &mut self.b
+    }
+
+    unsafe fn b_unchecked(self) -> u8 {
+        self.a
+    }
+
+    unsafe fn b_unchecked_mut(&mut self) -> &mut u8 {
+        &mut self.a
+    }
+
+    unsafe fn c_unchecked(&self) -> &u8 {
+        &self.b
+    }
+
+    unsafe fn c_unchecked_mut(&mut self) -> &mut u8 {
+        &mut self.a
+    }
+}
+
+struct D {
+    d: u8,
+    inner: A,
+}
+
+impl core::ops::Deref for D {
+    type Target = A;
+    fn deref(&self) -> &A {
+        &self.inner
+    }
+}
+
+impl core::ops::DerefMut for D {
+    fn deref_mut(&mut self) -> &mut A {
+        &mut self.inner
+    }
+}
+
+impl D {
+    fn a(&self) -> &u8 {
+        &self.b
+    }
+    fn a_mut(&mut self) -> &mut u8 {
+        &mut self.b
+    }
+
+    fn d(&self) -> &u8 {
+        &self.b
+    }
+    fn d_mut(&mut self) -> &mut u8 {
+        &mut self.b
+    }
+}
+
+fn main() {
+    // test code goes here
+}
diff --git a/src/tools/clippy/tests/ui/misnamed_getters.stderr b/src/tools/clippy/tests/ui/misnamed_getters.stderr
new file mode 100644 (file)
index 0000000..1e38a83
--- /dev/null
@@ -0,0 +1,166 @@
+error: getter function appears to return the wrong field
+  --> $DIR/misnamed_getters.rs:11:5
+   |
+LL | /     fn a(&self) -> &u8 {
+LL | |         &self.b
+   | |         ------- help: consider using: `&self.a`
+LL | |     }
+   | |_____^
+   |
+   = note: `-D clippy::misnamed-getters` implied by `-D warnings`
+
+error: getter function appears to return the wrong field
+  --> $DIR/misnamed_getters.rs:14:5
+   |
+LL | /     fn a_mut(&mut self) -> &mut u8 {
+LL | |         &mut self.b
+   | |         ----------- help: consider using: `&mut self.a`
+LL | |     }
+   | |_____^
+
+error: getter function appears to return the wrong field
+  --> $DIR/misnamed_getters.rs:18:5
+   |
+LL | /     fn b(self) -> u8 {
+LL | |         self.a
+   | |         ------ help: consider using: `self.b`
+LL | |     }
+   | |_____^
+
+error: getter function appears to return the wrong field
+  --> $DIR/misnamed_getters.rs:22:5
+   |
+LL | /     fn b_mut(&mut self) -> &mut u8 {
+LL | |         &mut self.a
+   | |         ----------- help: consider using: `&mut self.b`
+LL | |     }
+   | |_____^
+
+error: getter function appears to return the wrong field
+  --> $DIR/misnamed_getters.rs:26:5
+   |
+LL | /     fn c(&self) -> &u8 {
+LL | |         &self.b
+   | |         ------- help: consider using: `&self.c`
+LL | |     }
+   | |_____^
+
+error: getter function appears to return the wrong field
+  --> $DIR/misnamed_getters.rs:30:5
+   |
+LL | /     fn c_mut(&mut self) -> &mut u8 {
+LL | |         &mut self.a
+   | |         ----------- help: consider using: `&mut self.c`
+LL | |     }
+   | |_____^
+
+error: getter function appears to return the wrong field
+  --> $DIR/misnamed_getters.rs:41:5
+   |
+LL | /     unsafe fn a(&self) -> &u8 {
+LL | |         &self.b
+   | |         ------- help: consider using: `&self.a`
+LL | |     }
+   | |_____^
+
+error: getter function appears to return the wrong field
+  --> $DIR/misnamed_getters.rs:44:5
+   |
+LL | /     unsafe fn a_mut(&mut self) -> &mut u8 {
+LL | |         &mut self.b
+   | |         ----------- help: consider using: `&mut self.a`
+LL | |     }
+   | |_____^
+
+error: getter function appears to return the wrong field
+  --> $DIR/misnamed_getters.rs:48:5
+   |
+LL | /     unsafe fn b(self) -> u8 {
+LL | |         self.a
+   | |         ------ help: consider using: `self.b`
+LL | |     }
+   | |_____^
+
+error: getter function appears to return the wrong field
+  --> $DIR/misnamed_getters.rs:52:5
+   |
+LL | /     unsafe fn b_mut(&mut self) -> &mut u8 {
+LL | |         &mut self.a
+   | |         ----------- help: consider using: `&mut self.b`
+LL | |     }
+   | |_____^
+
+error: getter function appears to return the wrong field
+  --> $DIR/misnamed_getters.rs:64:5
+   |
+LL | /     unsafe fn a_unchecked(&self) -> &u8 {
+LL | |         &self.b
+   | |         ------- help: consider using: `&self.a`
+LL | |     }
+   | |_____^
+
+error: getter function appears to return the wrong field
+  --> $DIR/misnamed_getters.rs:67:5
+   |
+LL | /     unsafe fn a_unchecked_mut(&mut self) -> &mut u8 {
+LL | |         &mut self.b
+   | |         ----------- help: consider using: `&mut self.a`
+LL | |     }
+   | |_____^
+
+error: getter function appears to return the wrong field
+  --> $DIR/misnamed_getters.rs:71:5
+   |
+LL | /     unsafe fn b_unchecked(self) -> u8 {
+LL | |         self.a
+   | |         ------ help: consider using: `self.b`
+LL | |     }
+   | |_____^
+
+error: getter function appears to return the wrong field
+  --> $DIR/misnamed_getters.rs:75:5
+   |
+LL | /     unsafe fn b_unchecked_mut(&mut self) -> &mut u8 {
+LL | |         &mut self.a
+   | |         ----------- help: consider using: `&mut self.b`
+LL | |     }
+   | |_____^
+
+error: getter function appears to return the wrong field
+  --> $DIR/misnamed_getters.rs:107:5
+   |
+LL | /     fn a(&self) -> &u8 {
+LL | |         &self.b
+   | |         ------- help: consider using: `&self.a`
+LL | |     }
+   | |_____^
+
+error: getter function appears to return the wrong field
+  --> $DIR/misnamed_getters.rs:110:5
+   |
+LL | /     fn a_mut(&mut self) -> &mut u8 {
+LL | |         &mut self.b
+   | |         ----------- help: consider using: `&mut self.a`
+LL | |     }
+   | |_____^
+
+error: getter function appears to return the wrong field
+  --> $DIR/misnamed_getters.rs:114:5
+   |
+LL | /     fn d(&self) -> &u8 {
+LL | |         &self.b
+   | |         ------- help: consider using: `&self.d`
+LL | |     }
+   | |_____^
+
+error: getter function appears to return the wrong field
+  --> $DIR/misnamed_getters.rs:117:5
+   |
+LL | /     fn d_mut(&mut self) -> &mut u8 {
+LL | |         &mut self.b
+   | |         ----------- help: consider using: `&mut self.d`
+LL | |     }
+   | |_____^
+
+error: aborting due to 18 previous errors
+
index b950248ef942024d0e003fc5be16c8ba0c249101..75cace1816754e75eb17dca1d10e1063f528ac73 100644 (file)
@@ -7,7 +7,6 @@
 
 #![warn(clippy::missing_const_for_fn)]
 #![feature(start)]
-#![feature(custom_inner_attributes)]
 
 extern crate helper;
 extern crate proc_macro_with_span;
@@ -115,9 +114,8 @@ fn unstably_const_fn() {
     helper::unstably_const_fn()
 }
 
+#[clippy::msrv = "1.46.0"]
 mod const_fn_stabilized_after_msrv {
-    #![clippy::msrv = "1.46.0"]
-
     // Do not lint this because `u8::is_ascii_digit` is stabilized as a const function in 1.47.0.
     fn const_fn_stabilized_after_msrv(byte: u8) {
         byte.is_ascii_digit();
index b85e88784918d50401858472574b07902aadf6e0..0246c8622ed3adf6b7f6c7086843b83b4049b960 100644 (file)
@@ -1,6 +1,5 @@
 #![warn(clippy::missing_const_for_fn)]
 #![allow(incomplete_features, clippy::let_and_return)]
-#![feature(custom_inner_attributes)]
 
 use std::mem::transmute;
 
@@ -68,24 +67,21 @@ pub fn b(self, a: &A) -> B {
     }
 }
 
+#[clippy::msrv = "1.47.0"]
 mod const_fn_stabilized_before_msrv {
-    #![clippy::msrv = "1.47.0"]
-
     // This could be const because `u8::is_ascii_digit` is a stable const function in 1.47.
     fn const_fn_stabilized_before_msrv(byte: u8) {
         byte.is_ascii_digit();
     }
 }
 
+#[clippy::msrv = "1.45"]
 fn msrv_1_45() -> i32 {
-    #![clippy::msrv = "1.45"]
-
     45
 }
 
+#[clippy::msrv = "1.46"]
 fn msrv_1_46() -> i32 {
-    #![clippy::msrv = "1.46"]
-
     46
 }
 
index f8e221c82f1a5c4ba575433c3cdeb301577c60d3..955e1ed26340899c898c4eedcd508b384ac2c2f1 100644 (file)
@@ -1,5 +1,5 @@
 error: this could be a `const fn`
-  --> $DIR/could_be_const.rs:13:5
+  --> $DIR/could_be_const.rs:12:5
    |
 LL | /     pub fn new() -> Self {
 LL | |         Self { guess: 42 }
@@ -9,7 +9,7 @@ LL | |     }
    = note: `-D clippy::missing-const-for-fn` implied by `-D warnings`
 
 error: this could be a `const fn`
-  --> $DIR/could_be_const.rs:17:5
+  --> $DIR/could_be_const.rs:16:5
    |
 LL | /     fn const_generic_params<'a, T, const N: usize>(&self, b: &'a [T; N]) -> &'a [T; N] {
 LL | |         b
@@ -17,7 +17,7 @@ LL | |     }
    | |_____^
 
 error: this could be a `const fn`
-  --> $DIR/could_be_const.rs:23:1
+  --> $DIR/could_be_const.rs:22:1
    |
 LL | / fn one() -> i32 {
 LL | |     1
@@ -25,7 +25,7 @@ LL | | }
    | |_^
 
 error: this could be a `const fn`
-  --> $DIR/could_be_const.rs:28:1
+  --> $DIR/could_be_const.rs:27:1
    |
 LL | / fn two() -> i32 {
 LL | |     let abc = 2;
@@ -34,7 +34,7 @@ LL | | }
    | |_^
 
 error: this could be a `const fn`
-  --> $DIR/could_be_const.rs:34:1
+  --> $DIR/could_be_const.rs:33:1
    |
 LL | / fn string() -> String {
 LL | |     String::new()
@@ -42,7 +42,7 @@ LL | | }
    | |_^
 
 error: this could be a `const fn`
-  --> $DIR/could_be_const.rs:39:1
+  --> $DIR/could_be_const.rs:38:1
    |
 LL | / unsafe fn four() -> i32 {
 LL | |     4
@@ -50,7 +50,7 @@ LL | | }
    | |_^
 
 error: this could be a `const fn`
-  --> $DIR/could_be_const.rs:44:1
+  --> $DIR/could_be_const.rs:43:1
    |
 LL | / fn generic<T>(t: T) -> T {
 LL | |     t
@@ -58,7 +58,7 @@ LL | | }
    | |_^
 
 error: this could be a `const fn`
-  --> $DIR/could_be_const.rs:52:1
+  --> $DIR/could_be_const.rs:51:1
    |
 LL | / fn generic_arr<T: Copy>(t: [T; 1]) -> T {
 LL | |     t[0]
@@ -66,7 +66,7 @@ LL | | }
    | |_^
 
 error: this could be a `const fn`
-  --> $DIR/could_be_const.rs:65:9
+  --> $DIR/could_be_const.rs:64:9
    |
 LL | /         pub fn b(self, a: &A) -> B {
 LL | |             B
@@ -74,7 +74,7 @@ LL | |         }
    | |_________^
 
 error: this could be a `const fn`
-  --> $DIR/could_be_const.rs:75:5
+  --> $DIR/could_be_const.rs:73:5
    |
 LL | /     fn const_fn_stabilized_before_msrv(byte: u8) {
 LL | |         byte.is_ascii_digit();
@@ -82,11 +82,9 @@ LL | |     }
    | |_____^
 
 error: this could be a `const fn`
-  --> $DIR/could_be_const.rs:86:1
+  --> $DIR/could_be_const.rs:84:1
    |
 LL | / fn msrv_1_46() -> i32 {
-LL | |     #![clippy::msrv = "1.46"]
-LL | |
 LL | |     46
 LL | | }
    | |_^
index 85b6b639d5549c9b6636597617a8c486370a7863..4cb7f6b687f1195c3bb429b941c8ca256f6534d3 100644 (file)
@@ -1,13 +1,13 @@
 // run-rustfix
-#![feature(custom_inner_attributes, lint_reasons)]
-
-#[warn(clippy::all, clippy::needless_borrow)]
-#[allow(unused_variables)]
-#[allow(
+#![feature(lint_reasons)]
+#![allow(
+    unused,
     clippy::uninlined_format_args,
     clippy::unnecessary_mut_passed,
     clippy::unnecessary_to_owned
 )]
+#![warn(clippy::needless_borrow)]
+
 fn main() {
     let a = 5;
     let ref_a = &a;
@@ -171,14 +171,12 @@ impl<'a> Trait for &'a str {}
 
 fn h(_: &dyn Trait) {}
 
-#[allow(dead_code)]
 fn check_expect_suppression() {
     let a = 5;
     #[expect(clippy::needless_borrow)]
     let _ = x(&&a);
 }
 
-#[allow(dead_code)]
 mod issue9160 {
     pub struct S<F> {
         f: F,
@@ -267,7 +265,6 @@ where
 }
 
 // https://github.com/rust-lang/rust-clippy/pull/9136#pullrequestreview-1037379321
-#[allow(dead_code)]
 mod copyable_iterator {
     #[derive(Clone, Copy)]
     struct Iter;
@@ -287,25 +284,20 @@ mod copyable_iterator {
     }
 }
 
+#[clippy::msrv = "1.52.0"]
 mod under_msrv {
-    #![allow(dead_code)]
-    #![clippy::msrv = "1.52.0"]
-
     fn foo() {
         let _ = std::process::Command::new("ls").args(&["-a", "-l"]).status().unwrap();
     }
 }
 
+#[clippy::msrv = "1.53.0"]
 mod meets_msrv {
-    #![allow(dead_code)]
-    #![clippy::msrv = "1.53.0"]
-
     fn foo() {
         let _ = std::process::Command::new("ls").args(["-a", "-l"]).status().unwrap();
     }
 }
 
-#[allow(unused)]
 fn issue9383() {
     // Should not lint because unions need explicit deref when accessing field
     use std::mem::ManuallyDrop;
@@ -334,7 +326,6 @@ fn issue9383() {
     }
 }
 
-#[allow(dead_code)]
 fn closure_test() {
     let env = "env".to_owned();
     let arg = "arg".to_owned();
@@ -348,7 +339,6 @@ fn closure_test() {
     f(arg);
 }
 
-#[allow(dead_code)]
 mod significant_drop {
     #[derive(Debug)]
     struct X;
@@ -368,7 +358,6 @@ mod significant_drop {
     fn debug(_: impl std::fmt::Debug) {}
 }
 
-#[allow(dead_code)]
 mod used_exactly_once {
     fn foo(x: String) {
         use_x(x);
@@ -376,7 +365,6 @@ mod used_exactly_once {
     fn use_x(_: impl AsRef<str>) {}
 }
 
-#[allow(dead_code)]
 mod used_more_than_once {
     fn foo(x: String) {
         use_x(&x);
@@ -387,7 +375,6 @@ mod used_more_than_once {
 }
 
 // https://github.com/rust-lang/rust-clippy/issues/9111#issuecomment-1277114280
-#[allow(dead_code)]
 mod issue_9111 {
     struct A;
 
@@ -409,7 +396,6 @@ mod issue_9111 {
     }
 }
 
-#[allow(dead_code)]
 mod issue_9710 {
     fn main() {
         let string = String::new();
@@ -421,7 +407,6 @@ mod issue_9710 {
     fn f<T: AsRef<str>>(_: T) {}
 }
 
-#[allow(dead_code)]
 mod issue_9739 {
     fn foo<D: std::fmt::Display>(_it: impl IntoIterator<Item = D>) {}
 
@@ -434,7 +419,6 @@ mod issue_9739 {
     }
 }
 
-#[allow(dead_code)]
 mod issue_9739_method_variant {
     struct S;
 
@@ -451,7 +435,6 @@ mod issue_9739_method_variant {
     }
 }
 
-#[allow(dead_code)]
 mod issue_9782 {
     fn foo<T: AsRef<[u8]>>(t: T) {
         println!("{}", std::mem::size_of::<T>());
@@ -475,7 +458,6 @@ mod issue_9782 {
     }
 }
 
-#[allow(dead_code)]
 mod issue_9782_type_relative_variant {
     struct S;
 
@@ -493,7 +475,6 @@ mod issue_9782_type_relative_variant {
     }
 }
 
-#[allow(dead_code)]
 mod issue_9782_method_variant {
     struct S;
 
index 7b97bcf3817ec0bc60c4b93acdfdabf1de063a70..9a01190ed8dbd585127276cde688afa19fd07730 100644 (file)
@@ -1,13 +1,13 @@
 // run-rustfix
-#![feature(custom_inner_attributes, lint_reasons)]
-
-#[warn(clippy::all, clippy::needless_borrow)]
-#[allow(unused_variables)]
-#[allow(
+#![feature(lint_reasons)]
+#![allow(
+    unused,
     clippy::uninlined_format_args,
     clippy::unnecessary_mut_passed,
     clippy::unnecessary_to_owned
 )]
+#![warn(clippy::needless_borrow)]
+
 fn main() {
     let a = 5;
     let ref_a = &a;
@@ -171,14 +171,12 @@ impl<'a> Trait for &'a str {}
 
 fn h(_: &dyn Trait) {}
 
-#[allow(dead_code)]
 fn check_expect_suppression() {
     let a = 5;
     #[expect(clippy::needless_borrow)]
     let _ = x(&&a);
 }
 
-#[allow(dead_code)]
 mod issue9160 {
     pub struct S<F> {
         f: F,
@@ -267,7 +265,6 @@ fn multiple_constraints_normalizes_to_different<T, U, V>(_: T, _: U)
 }
 
 // https://github.com/rust-lang/rust-clippy/pull/9136#pullrequestreview-1037379321
-#[allow(dead_code)]
 mod copyable_iterator {
     #[derive(Clone, Copy)]
     struct Iter;
@@ -287,25 +284,20 @@ fn warn(mut x: &mut Iter) {
     }
 }
 
+#[clippy::msrv = "1.52.0"]
 mod under_msrv {
-    #![allow(dead_code)]
-    #![clippy::msrv = "1.52.0"]
-
     fn foo() {
         let _ = std::process::Command::new("ls").args(&["-a", "-l"]).status().unwrap();
     }
 }
 
+#[clippy::msrv = "1.53.0"]
 mod meets_msrv {
-    #![allow(dead_code)]
-    #![clippy::msrv = "1.53.0"]
-
     fn foo() {
         let _ = std::process::Command::new("ls").args(&["-a", "-l"]).status().unwrap();
     }
 }
 
-#[allow(unused)]
 fn issue9383() {
     // Should not lint because unions need explicit deref when accessing field
     use std::mem::ManuallyDrop;
@@ -334,7 +326,6 @@ union Ocean {
     }
 }
 
-#[allow(dead_code)]
 fn closure_test() {
     let env = "env".to_owned();
     let arg = "arg".to_owned();
@@ -348,7 +339,6 @@ fn closure_test() {
     f(arg);
 }
 
-#[allow(dead_code)]
 mod significant_drop {
     #[derive(Debug)]
     struct X;
@@ -368,7 +358,6 @@ fn foo(x: X, y: Y) {
     fn debug(_: impl std::fmt::Debug) {}
 }
 
-#[allow(dead_code)]
 mod used_exactly_once {
     fn foo(x: String) {
         use_x(&x);
@@ -376,7 +365,6 @@ fn foo(x: String) {
     fn use_x(_: impl AsRef<str>) {}
 }
 
-#[allow(dead_code)]
 mod used_more_than_once {
     fn foo(x: String) {
         use_x(&x);
@@ -387,7 +375,6 @@ fn use_x_again(_: impl AsRef<str>) {}
 }
 
 // https://github.com/rust-lang/rust-clippy/issues/9111#issuecomment-1277114280
-#[allow(dead_code)]
 mod issue_9111 {
     struct A;
 
@@ -409,7 +396,6 @@ fn main() {
     }
 }
 
-#[allow(dead_code)]
 mod issue_9710 {
     fn main() {
         let string = String::new();
@@ -421,7 +407,6 @@ fn main() {
     fn f<T: AsRef<str>>(_: T) {}
 }
 
-#[allow(dead_code)]
 mod issue_9739 {
     fn foo<D: std::fmt::Display>(_it: impl IntoIterator<Item = D>) {}
 
@@ -434,7 +419,6 @@ fn main() {
     }
 }
 
-#[allow(dead_code)]
 mod issue_9739_method_variant {
     struct S;
 
@@ -451,7 +435,6 @@ fn main() {
     }
 }
 
-#[allow(dead_code)]
 mod issue_9782 {
     fn foo<T: AsRef<[u8]>>(t: T) {
         println!("{}", std::mem::size_of::<T>());
@@ -475,7 +458,6 @@ fn main() {
     }
 }
 
-#[allow(dead_code)]
 mod issue_9782_type_relative_variant {
     struct S;
 
@@ -493,7 +475,6 @@ fn main() {
     }
 }
 
-#[allow(dead_code)]
 mod issue_9782_method_variant {
     struct S;
 
index 485e6b84c868b11972932b16a35f6e664e7ae6f4..d26c317124b8d18d3dc900d31c8badce92e20af1 100644 (file)
@@ -163,55 +163,55 @@ LL |     let _ = std::fs::write("x", &"".to_string());
    |                                 ^^^^^^^^^^^^^^^ help: change this to: `"".to_string()`
 
 error: this expression borrows a value the compiler would automatically borrow
-  --> $DIR/needless_borrow.rs:192:13
+  --> $DIR/needless_borrow.rs:190: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:201:13
+  --> $DIR/needless_borrow.rs:199:13
    |
 LL |             (&mut self.f)()
    |             ^^^^^^^^^^^^^ help: change this to: `(self.f)`
 
 error: the borrowed expression implements the required traits
-  --> $DIR/needless_borrow.rs:286:20
+  --> $DIR/needless_borrow.rs:283:20
    |
 LL |         takes_iter(&mut x)
    |                    ^^^^^^ help: change this to: `x`
 
 error: the borrowed expression implements the required traits
-  --> $DIR/needless_borrow.rs:304:55
+  --> $DIR/needless_borrow.rs:297:55
    |
 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:344:37
+  --> $DIR/needless_borrow.rs:335:37
    |
 LL |         let _ = std::fs::write("x", &arg);
    |                                     ^^^^ help: change this to: `arg`
 
 error: the borrowed expression implements the required traits
-  --> $DIR/needless_borrow.rs:345:37
+  --> $DIR/needless_borrow.rs:336:37
    |
 LL |         let _ = std::fs::write("x", &loc);
    |                                     ^^^^ help: change this to: `loc`
 
 error: the borrowed expression implements the required traits
-  --> $DIR/needless_borrow.rs:364:15
+  --> $DIR/needless_borrow.rs:354:15
    |
 LL |         debug(&x);
    |               ^^ help: change this to: `x`
 
 error: the borrowed expression implements the required traits
-  --> $DIR/needless_borrow.rs:374:15
+  --> $DIR/needless_borrow.rs:363:15
    |
 LL |         use_x(&x);
    |               ^^ help: change this to: `x`
 
 error: the borrowed expression implements the required traits
-  --> $DIR/needless_borrow.rs:474:13
+  --> $DIR/needless_borrow.rs:457:13
    |
 LL |         foo(&a);
    |             ^^ help: change this to: `a`
index ba9d15e59d0e45376374c23b07b87c661def3a17..7eaca571992f46d971bea18739e3b7c50e565381 100644 (file)
@@ -8,7 +8,6 @@
     dead_code,
     unused_must_use
 )]
-#![feature(custom_inner_attributes)]
 
 struct TO {
     magic: Option<usize>,
index 3a6523e8fe872a94b172c851d1c997f9a1ed9350..960bc7b78983f96d17d454b568f9c17eafa72aa6 100644 (file)
@@ -8,7 +8,6 @@
     dead_code,
     unused_must_use
 )]
-#![feature(custom_inner_attributes)]
 
 struct TO {
     magic: Option<usize>,
index f8308e24e7712e62adbf9b248757a3c9b0b32abb..d1f89e326c67c3ab65b1dd7e6f31eb52e0093c01 100644 (file)
@@ -1,5 +1,5 @@
 error: question mark operator is useless here
-  --> $DIR/needless_question_mark.rs:23:12
+  --> $DIR/needless_question_mark.rs:22:12
    |
 LL |     return Some(to.magic?);
    |            ^^^^^^^^^^^^^^^ help: try removing question mark and `Some()`: `to.magic`
@@ -7,67 +7,67 @@ LL |     return Some(to.magic?);
    = note: `-D clippy::needless-question-mark` implied by `-D warnings`
 
 error: question mark operator is useless here
-  --> $DIR/needless_question_mark.rs:31:12
+  --> $DIR/needless_question_mark.rs:30:12
    |
 LL |     return Some(to.magic?)
    |            ^^^^^^^^^^^^^^^ help: try removing question mark and `Some()`: `to.magic`
 
 error: question mark operator is useless here
-  --> $DIR/needless_question_mark.rs:36:5
+  --> $DIR/needless_question_mark.rs:35:5
    |
 LL |     Some(to.magic?)
    |     ^^^^^^^^^^^^^^^ help: try removing question mark and `Some()`: `to.magic`
 
 error: question mark operator is useless here
-  --> $DIR/needless_question_mark.rs:41:21
+  --> $DIR/needless_question_mark.rs:40:21
    |
 LL |     to.and_then(|t| Some(t.magic?))
    |                     ^^^^^^^^^^^^^^ help: try removing question mark and `Some()`: `t.magic`
 
 error: question mark operator is useless here
-  --> $DIR/needless_question_mark.rs:50:9
+  --> $DIR/needless_question_mark.rs:49:9
    |
 LL |         Some(t.magic?)
    |         ^^^^^^^^^^^^^^ help: try removing question mark and `Some()`: `t.magic`
 
 error: question mark operator is useless here
-  --> $DIR/needless_question_mark.rs:55:12
+  --> $DIR/needless_question_mark.rs:54:12
    |
 LL |     return Ok(tr.magic?);
    |            ^^^^^^^^^^^^^ help: try removing question mark and `Ok()`: `tr.magic`
 
 error: question mark operator is useless here
-  --> $DIR/needless_question_mark.rs:62:12
+  --> $DIR/needless_question_mark.rs:61:12
    |
 LL |     return Ok(tr.magic?)
    |            ^^^^^^^^^^^^^ help: try removing question mark and `Ok()`: `tr.magic`
 
 error: question mark operator is useless here
-  --> $DIR/needless_question_mark.rs:66:5
+  --> $DIR/needless_question_mark.rs:65:5
    |
 LL |     Ok(tr.magic?)
    |     ^^^^^^^^^^^^^ help: try removing question mark and `Ok()`: `tr.magic`
 
 error: question mark operator is useless here
-  --> $DIR/needless_question_mark.rs:70:21
+  --> $DIR/needless_question_mark.rs:69:21
    |
 LL |     tr.and_then(|t| Ok(t.magic?))
    |                     ^^^^^^^^^^^^ help: try removing question mark and `Ok()`: `t.magic`
 
 error: question mark operator is useless here
-  --> $DIR/needless_question_mark.rs:78:9
+  --> $DIR/needless_question_mark.rs:77:9
    |
 LL |         Ok(t.magic?)
    |         ^^^^^^^^^^^^ help: try removing question mark and `Ok()`: `t.magic`
 
 error: question mark operator is useless here
-  --> $DIR/needless_question_mark.rs:85:16
+  --> $DIR/needless_question_mark.rs:84:16
    |
 LL |         return Ok(t.magic?);
    |                ^^^^^^^^^^^^ help: try removing question mark and `Ok()`: `t.magic`
 
 error: question mark operator is useless here
-  --> $DIR/needless_question_mark.rs:120:27
+  --> $DIR/needless_question_mark.rs:119:27
    |
 LL |         || -> Option<_> { Some(Some($expr)?) }()
    |                           ^^^^^^^^^^^^^^^^^^ help: try removing question mark and `Some()`: `Some($expr)`
@@ -78,13 +78,13 @@ LL |     let _x = some_and_qmark_in_macro!(x?);
    = note: this error originates in the macro `some_and_qmark_in_macro` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: question mark operator is useless here
-  --> $DIR/needless_question_mark.rs:131:5
+  --> $DIR/needless_question_mark.rs:130:5
    |
 LL |     Some(to.magic?)
    |     ^^^^^^^^^^^^^^^ help: try removing question mark and `Some()`: `to.magic`
 
 error: question mark operator is useless here
-  --> $DIR/needless_question_mark.rs:139:5
+  --> $DIR/needless_question_mark.rs:138:5
    |
 LL |     Ok(s.magic?)
    |     ^^^^^^^^^^^^ help: try removing question mark and `Ok()`: `s.magic`
index d2163b14fcadca01e1c205a3ce89a94f7a865fde..4386aaec49e2437751803ac8f9ce216c17e79f07 100644 (file)
@@ -59,14 +59,11 @@ fn test_macro_call() -> i32 {
 }
 
 fn test_void_fun() {
-    
 }
 
 fn test_void_if_fun(b: bool) {
     if b {
-        
     } else {
-        
     }
 }
 
@@ -82,7 +79,6 @@ fn test_nested_match(x: u32) {
         0 => (),
         1 => {
             let _ = 42;
-            
         },
         _ => (),
     }
@@ -126,7 +122,6 @@ mod issue6501 {
 
     fn test_closure() {
         let _ = || {
-            
         };
         let _ = || {};
     }
@@ -179,14 +174,11 @@ async fn async_test_macro_call() -> i32 {
 }
 
 async fn async_test_void_fun() {
-    
 }
 
 async fn async_test_void_if_fun(b: bool) {
     if b {
-        
     } else {
-        
     }
 }
 
@@ -269,4 +261,15 @@ fn issue9503(x: usize) -> isize {
     }
 }
 
+mod issue9416 {
+    pub fn with_newline() {
+        let _ = 42;
+    }
+
+    #[rustfmt::skip]
+    pub fn oneline() {
+        let _ = 42;
+    }
+}
+
 fn main() {}
index 114414b5fac76b7d522ac6e246293e2ccb78533b..666dc54b76b412b2267e083d3d130929cc07309e 100644 (file)
@@ -269,4 +269,17 @@ fn issue9503(x: usize) -> isize {
     };
 }
 
+mod issue9416 {
+    pub fn with_newline() {
+        let _ = 42;
+
+        return;
+    }
+
+    #[rustfmt::skip]
+    pub fn oneline() {
+        let _ = 42; return;
+    }
+}
+
 fn main() {}
index 047fb6c2311a2153e6db1cc8c69df5867d485782..a8b5d86cd5581f46a415a3c06f6e2d88cfa0ae60 100644 (file)
@@ -72,26 +72,32 @@ LL |     return the_answer!();
    = help: remove `return`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:62:5
+  --> $DIR/needless_return.rs:61:21
    |
-LL |     return;
-   |     ^^^^^^
+LL |   fn test_void_fun() {
+   |  _____________________^
+LL | |     return;
+   | |__________^
    |
    = help: remove `return`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:67:9
+  --> $DIR/needless_return.rs:66:11
    |
-LL |         return;
-   |         ^^^^^^
+LL |       if b {
+   |  ___________^
+LL | |         return;
+   | |______________^
    |
    = help: remove `return`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:69:9
+  --> $DIR/needless_return.rs:68:13
    |
-LL |         return;
-   |         ^^^^^^
+LL |       } else {
+   |  _____________^
+LL | |         return;
+   | |______________^
    |
    = help: remove `return`
 
@@ -104,10 +110,12 @@ LL |         _ => return,
    = help: replace `return` with a unit value
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:85:13
+  --> $DIR/needless_return.rs:84:24
    |
-LL |             return;
-   |             ^^^^^^
+LL |               let _ = 42;
+   |  ________________________^
+LL | |             return;
+   | |__________________^
    |
    = help: remove `return`
 
@@ -144,10 +152,12 @@ LL |         bar.unwrap_or_else(|_| return)
    = help: replace `return` with an empty block
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:129:13
+  --> $DIR/needless_return.rs:128:21
    |
-LL |             return;
-   |             ^^^^^^
+LL |           let _ = || {
+   |  _____________________^
+LL | |             return;
+   | |__________________^
    |
    = help: remove `return`
 
@@ -240,26 +250,32 @@ LL |     return the_answer!();
    = help: remove `return`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:182:5
+  --> $DIR/needless_return.rs:181:33
    |
-LL |     return;
-   |     ^^^^^^
+LL |   async fn async_test_void_fun() {
+   |  _________________________________^
+LL | |     return;
+   | |__________^
    |
    = help: remove `return`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:187:9
+  --> $DIR/needless_return.rs:186:11
    |
-LL |         return;
-   |         ^^^^^^
+LL |       if b {
+   |  ___________^
+LL | |         return;
+   | |______________^
    |
    = help: remove `return`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:189:9
+  --> $DIR/needless_return.rs:188:13
    |
-LL |         return;
-   |         ^^^^^^
+LL |       } else {
+   |  _____________^
+LL | |         return;
+   | |______________^
    |
    = help: remove `return`
 
@@ -351,5 +367,24 @@ LL |             return !*(x as *const isize);
    |
    = help: remove `return`
 
-error: aborting due to 44 previous errors
+error: unneeded `return` statement
+  --> $DIR/needless_return.rs:274:20
+   |
+LL |           let _ = 42;
+   |  ____________________^
+LL | |
+LL | |         return;
+   | |______________^
+   |
+   = help: remove `return`
+
+error: unneeded `return` statement
+  --> $DIR/needless_return.rs:281:20
+   |
+LL |         let _ = 42; return;
+   |                    ^^^^^^^
+   |
+   = help: remove `return`
+
+error: aborting due to 46 previous errors
 
index 61f5fc4e679edafbb609cfa70dd550ff3df2e39e..5496031fefabf9f9fa8335328850685a5e13621e 100644 (file)
@@ -1,7 +1,6 @@
 // run-rustfix
 // edition:2018
 
-#![feature(custom_inner_attributes)]
 #![warn(clippy::needless_splitn)]
 #![allow(clippy::iter_skip_next, clippy::iter_nth_zero, clippy::manual_split_once)]
 
@@ -40,8 +39,8 @@ fn _question_mark(s: &str) -> Option<()> {
     Some(())
 }
 
+#[clippy::msrv = "1.51"]
 fn _test_msrv() {
-    #![clippy::msrv = "1.51"]
     // `manual_split_once` MSRV shouldn't apply to `needless_splitn`
     let _ = "key=value".split('=').nth(0).unwrap();
 }
index 71d9a7077faa6f354e9475507b456d8e53e884e9..35c2465bae13138f2da781f87ed30d800f84e35a 100644 (file)
@@ -1,7 +1,6 @@
 // run-rustfix
 // edition:2018
 
-#![feature(custom_inner_attributes)]
 #![warn(clippy::needless_splitn)]
 #![allow(clippy::iter_skip_next, clippy::iter_nth_zero, clippy::manual_split_once)]
 
@@ -40,8 +39,8 @@ fn _question_mark(s: &str) -> Option<()> {
     Some(())
 }
 
+#[clippy::msrv = "1.51"]
 fn _test_msrv() {
-    #![clippy::msrv = "1.51"]
     // `manual_split_once` MSRV shouldn't apply to `needless_splitn`
     let _ = "key=value".splitn(2, '=').nth(0).unwrap();
 }
index f112b29e7f2066ccb0751f049d479b45d5a79c58..f607d8e1ab5f40dd97e380dc78c55c2bf98353f1 100644 (file)
@@ -1,5 +1,5 @@
 error: unnecessary use of `splitn`
-  --> $DIR/needless_splitn.rs:15:13
+  --> $DIR/needless_splitn.rs:14:13
    |
 LL |     let _ = str.splitn(2, '=').next();
    |             ^^^^^^^^^^^^^^^^^^ help: try this: `str.split('=')`
@@ -7,73 +7,73 @@ LL |     let _ = str.splitn(2, '=').next();
    = note: `-D clippy::needless-splitn` implied by `-D warnings`
 
 error: unnecessary use of `splitn`
-  --> $DIR/needless_splitn.rs:16:13
+  --> $DIR/needless_splitn.rs:15:13
    |
 LL |     let _ = str.splitn(2, '=').nth(0);
    |             ^^^^^^^^^^^^^^^^^^ help: try this: `str.split('=')`
 
 error: unnecessary use of `splitn`
-  --> $DIR/needless_splitn.rs:19:18
+  --> $DIR/needless_splitn.rs:18:18
    |
 LL |     let (_, _) = str.splitn(3, '=').next_tuple().unwrap();
    |                  ^^^^^^^^^^^^^^^^^^ help: try this: `str.split('=')`
 
 error: unnecessary use of `rsplitn`
-  --> $DIR/needless_splitn.rs:22:13
+  --> $DIR/needless_splitn.rs:21:13
    |
 LL |     let _ = str.rsplitn(2, '=').next();
    |             ^^^^^^^^^^^^^^^^^^^ help: try this: `str.rsplit('=')`
 
 error: unnecessary use of `rsplitn`
-  --> $DIR/needless_splitn.rs:23:13
+  --> $DIR/needless_splitn.rs:22:13
    |
 LL |     let _ = str.rsplitn(2, '=').nth(0);
    |             ^^^^^^^^^^^^^^^^^^^ help: try this: `str.rsplit('=')`
 
 error: unnecessary use of `rsplitn`
-  --> $DIR/needless_splitn.rs:26:18
+  --> $DIR/needless_splitn.rs:25:18
    |
 LL |     let (_, _) = str.rsplitn(3, '=').next_tuple().unwrap();
    |                  ^^^^^^^^^^^^^^^^^^^ help: try this: `str.rsplit('=')`
 
 error: unnecessary use of `splitn`
-  --> $DIR/needless_splitn.rs:28:13
+  --> $DIR/needless_splitn.rs:27:13
    |
 LL |     let _ = str.splitn(5, '=').next();
    |             ^^^^^^^^^^^^^^^^^^ help: try this: `str.split('=')`
 
 error: unnecessary use of `splitn`
-  --> $DIR/needless_splitn.rs:29:13
+  --> $DIR/needless_splitn.rs:28:13
    |
 LL |     let _ = str.splitn(5, '=').nth(3);
    |             ^^^^^^^^^^^^^^^^^^ help: try this: `str.split('=')`
 
 error: unnecessary use of `splitn`
-  --> $DIR/needless_splitn.rs:35:13
+  --> $DIR/needless_splitn.rs:34:13
    |
 LL |     let _ = s.splitn(2, '=').next()?;
    |             ^^^^^^^^^^^^^^^^ help: try this: `s.split('=')`
 
 error: unnecessary use of `splitn`
-  --> $DIR/needless_splitn.rs:36:13
+  --> $DIR/needless_splitn.rs:35:13
    |
 LL |     let _ = s.splitn(2, '=').nth(0)?;
    |             ^^^^^^^^^^^^^^^^ help: try this: `s.split('=')`
 
 error: unnecessary use of `rsplitn`
-  --> $DIR/needless_splitn.rs:37:13
+  --> $DIR/needless_splitn.rs:36:13
    |
 LL |     let _ = s.rsplitn(2, '=').next()?;
    |             ^^^^^^^^^^^^^^^^^ help: try this: `s.rsplit('=')`
 
 error: unnecessary use of `rsplitn`
-  --> $DIR/needless_splitn.rs:38:13
+  --> $DIR/needless_splitn.rs:37:13
    |
 LL |     let _ = s.rsplitn(2, '=').nth(0)?;
    |             ^^^^^^^^^^^^^^^^^ help: try this: `s.rsplit('=')`
 
 error: unnecessary use of `splitn`
-  --> $DIR/needless_splitn.rs:46:13
+  --> $DIR/needless_splitn.rs:45:13
    |
 LL |     let _ = "key=value".splitn(2, '=').nth(0).unwrap();
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `"key=value".split('=')`
index bc376d0d7fb391eed0b6806779ed5bfec1063b47..d124d133faa21ff8418703726c06ae7a941f9f35 100644 (file)
@@ -1,6 +1,5 @@
 // run-rustfix
 
-#![feature(custom_inner_attributes)]
 #![allow(unused, clippy::redundant_clone)]
 #![warn(clippy::option_as_ref_deref)]
 
@@ -44,16 +43,14 @@ fn main() {
     let _ = opt.as_deref();
 }
 
+#[clippy::msrv = "1.39"]
 fn msrv_1_39() {
-    #![clippy::msrv = "1.39"]
-
     let opt = Some(String::from("123"));
     let _ = opt.as_ref().map(String::as_str);
 }
 
+#[clippy::msrv = "1.40"]
 fn msrv_1_40() {
-    #![clippy::msrv = "1.40"]
-
     let opt = Some(String::from("123"));
     let _ = opt.as_deref();
 }
index ba3a2eedc225cf42b27803ce102c4a4713344fb6..86e354c6716bba5da71df2c5fa42f95d4fd42656 100644 (file)
@@ -1,6 +1,5 @@
 // run-rustfix
 
-#![feature(custom_inner_attributes)]
 #![allow(unused, clippy::redundant_clone)]
 #![warn(clippy::option_as_ref_deref)]
 
@@ -47,16 +46,14 @@ fn main() {
     let _ = opt.as_ref().map(std::ops::Deref::deref);
 }
 
+#[clippy::msrv = "1.39"]
 fn msrv_1_39() {
-    #![clippy::msrv = "1.39"]
-
     let opt = Some(String::from("123"));
     let _ = opt.as_ref().map(String::as_str);
 }
 
+#[clippy::msrv = "1.40"]
 fn msrv_1_40() {
-    #![clippy::msrv = "1.40"]
-
     let opt = Some(String::from("123"));
     let _ = opt.as_ref().map(String::as_str);
 }
index 7de8b3b6ba4355c55d3fb0a7712f7e43253e1596..e471b56eea8170ef94c98de551e0c41e4d13736f 100644 (file)
@@ -1,5 +1,5 @@
 error: called `.as_ref().map(Deref::deref)` on an Option value. This can be done more directly by calling `opt.clone().as_deref()` instead
-  --> $DIR/option_as_ref_deref.rs:14:13
+  --> $DIR/option_as_ref_deref.rs:13:13
    |
 LL |     let _ = opt.clone().as_ref().map(Deref::deref).map(str::len);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using as_deref instead: `opt.clone().as_deref()`
@@ -7,7 +7,7 @@ LL |     let _ = opt.clone().as_ref().map(Deref::deref).map(str::len);
    = note: `-D clippy::option-as-ref-deref` implied by `-D warnings`
 
 error: called `.as_ref().map(Deref::deref)` on an Option value. This can be done more directly by calling `opt.clone().as_deref()` instead
-  --> $DIR/option_as_ref_deref.rs:17:13
+  --> $DIR/option_as_ref_deref.rs:16:13
    |
 LL |       let _ = opt.clone()
    |  _____________^
@@ -17,97 +17,97 @@ LL | |         )
    | |_________^ help: try using as_deref instead: `opt.clone().as_deref()`
 
 error: called `.as_mut().map(DerefMut::deref_mut)` on an Option value. This can be done more directly by calling `opt.as_deref_mut()` instead
-  --> $DIR/option_as_ref_deref.rs:23:13
+  --> $DIR/option_as_ref_deref.rs:22:13
    |
 LL |     let _ = opt.as_mut().map(DerefMut::deref_mut);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using as_deref_mut instead: `opt.as_deref_mut()`
 
 error: called `.as_ref().map(String::as_str)` on an Option value. This can be done more directly by calling `opt.as_deref()` instead
-  --> $DIR/option_as_ref_deref.rs:25:13
+  --> $DIR/option_as_ref_deref.rs:24:13
    |
 LL |     let _ = opt.as_ref().map(String::as_str);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using as_deref instead: `opt.as_deref()`
 
 error: called `.as_ref().map(|x| x.as_str())` on an Option value. This can be done more directly by calling `opt.as_deref()` instead
-  --> $DIR/option_as_ref_deref.rs:26:13
+  --> $DIR/option_as_ref_deref.rs:25:13
    |
 LL |     let _ = opt.as_ref().map(|x| x.as_str());
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using as_deref instead: `opt.as_deref()`
 
 error: called `.as_mut().map(String::as_mut_str)` on an Option value. This can be done more directly by calling `opt.as_deref_mut()` instead
-  --> $DIR/option_as_ref_deref.rs:27:13
+  --> $DIR/option_as_ref_deref.rs:26:13
    |
 LL |     let _ = opt.as_mut().map(String::as_mut_str);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using as_deref_mut instead: `opt.as_deref_mut()`
 
 error: called `.as_mut().map(|x| x.as_mut_str())` on an Option value. This can be done more directly by calling `opt.as_deref_mut()` instead
-  --> $DIR/option_as_ref_deref.rs:28:13
+  --> $DIR/option_as_ref_deref.rs:27:13
    |
 LL |     let _ = opt.as_mut().map(|x| x.as_mut_str());
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using as_deref_mut instead: `opt.as_deref_mut()`
 
 error: called `.as_ref().map(CString::as_c_str)` on an Option value. This can be done more directly by calling `Some(CString::new(vec![]).unwrap()).as_deref()` instead
-  --> $DIR/option_as_ref_deref.rs:29:13
+  --> $DIR/option_as_ref_deref.rs:28:13
    |
 LL |     let _ = Some(CString::new(vec![]).unwrap()).as_ref().map(CString::as_c_str);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using as_deref instead: `Some(CString::new(vec![]).unwrap()).as_deref()`
 
 error: called `.as_ref().map(OsString::as_os_str)` on an Option value. This can be done more directly by calling `Some(OsString::new()).as_deref()` instead
-  --> $DIR/option_as_ref_deref.rs:30:13
+  --> $DIR/option_as_ref_deref.rs:29:13
    |
 LL |     let _ = Some(OsString::new()).as_ref().map(OsString::as_os_str);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using as_deref instead: `Some(OsString::new()).as_deref()`
 
 error: called `.as_ref().map(PathBuf::as_path)` on an Option value. This can be done more directly by calling `Some(PathBuf::new()).as_deref()` instead
-  --> $DIR/option_as_ref_deref.rs:31:13
+  --> $DIR/option_as_ref_deref.rs:30:13
    |
 LL |     let _ = Some(PathBuf::new()).as_ref().map(PathBuf::as_path);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using as_deref instead: `Some(PathBuf::new()).as_deref()`
 
 error: called `.as_ref().map(Vec::as_slice)` on an Option value. This can be done more directly by calling `Some(Vec::<()>::new()).as_deref()` instead
-  --> $DIR/option_as_ref_deref.rs:32:13
+  --> $DIR/option_as_ref_deref.rs:31:13
    |
 LL |     let _ = Some(Vec::<()>::new()).as_ref().map(Vec::as_slice);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using as_deref instead: `Some(Vec::<()>::new()).as_deref()`
 
 error: called `.as_mut().map(Vec::as_mut_slice)` on an Option value. This can be done more directly by calling `Some(Vec::<()>::new()).as_deref_mut()` instead
-  --> $DIR/option_as_ref_deref.rs:33:13
+  --> $DIR/option_as_ref_deref.rs:32:13
    |
 LL |     let _ = Some(Vec::<()>::new()).as_mut().map(Vec::as_mut_slice);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using as_deref_mut instead: `Some(Vec::<()>::new()).as_deref_mut()`
 
 error: called `.as_ref().map(|x| x.deref())` on an Option value. This can be done more directly by calling `opt.as_deref()` instead
-  --> $DIR/option_as_ref_deref.rs:35:13
+  --> $DIR/option_as_ref_deref.rs:34:13
    |
 LL |     let _ = opt.as_ref().map(|x| x.deref());
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using as_deref instead: `opt.as_deref()`
 
 error: called `.as_mut().map(|x| x.deref_mut())` on an Option value. This can be done more directly by calling `opt.clone().as_deref_mut()` instead
-  --> $DIR/option_as_ref_deref.rs:36:13
+  --> $DIR/option_as_ref_deref.rs:35:13
    |
 LL |     let _ = opt.clone().as_mut().map(|x| x.deref_mut()).map(|x| x.len());
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using as_deref_mut instead: `opt.clone().as_deref_mut()`
 
 error: called `.as_ref().map(|x| &**x)` on an Option value. This can be done more directly by calling `opt.as_deref()` instead
-  --> $DIR/option_as_ref_deref.rs:43:13
+  --> $DIR/option_as_ref_deref.rs:42:13
    |
 LL |     let _ = opt.as_ref().map(|x| &**x);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using as_deref instead: `opt.as_deref()`
 
 error: called `.as_mut().map(|x| &mut **x)` on an Option value. This can be done more directly by calling `opt.as_deref_mut()` instead
-  --> $DIR/option_as_ref_deref.rs:44:13
+  --> $DIR/option_as_ref_deref.rs:43:13
    |
 LL |     let _ = opt.as_mut().map(|x| &mut **x);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using as_deref_mut instead: `opt.as_deref_mut()`
 
 error: called `.as_ref().map(std::ops::Deref::deref)` on an Option value. This can be done more directly by calling `opt.as_deref()` instead
-  --> $DIR/option_as_ref_deref.rs:47:13
+  --> $DIR/option_as_ref_deref.rs:46:13
    |
 LL |     let _ = opt.as_ref().map(std::ops::Deref::deref);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using as_deref instead: `opt.as_deref()`
 
 error: called `.as_ref().map(String::as_str)` on an Option value. This can be done more directly by calling `opt.as_deref()` instead
-  --> $DIR/option_as_ref_deref.rs:61:13
+  --> $DIR/option_as_ref_deref.rs:58:13
    |
 LL |     let _ = opt.as_ref().map(String::as_str);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using as_deref instead: `opt.as_deref()`
index bea6be66a8e025ef2f4468b5bb41e556c4c4614c..df36a9b842bf7f9f57066dc0c743393c397ce49a 100644 (file)
@@ -2,7 +2,6 @@
 // aux-build:macro_rules.rs
 
 #![warn(clippy::ptr_as_ptr)]
-#![feature(custom_inner_attributes)]
 
 extern crate macro_rules;
 
@@ -45,8 +44,8 @@ fn main() {
     let _ = macro_rules::ptr_as_ptr_cast!(ptr);
 }
 
+#[clippy::msrv = "1.37"]
 fn _msrv_1_37() {
-    #![clippy::msrv = "1.37"]
     let ptr: *const u32 = &42_u32;
     let mut_ptr: *mut u32 = &mut 42_u32;
 
@@ -55,8 +54,8 @@ fn _msrv_1_37() {
     let _ = mut_ptr as *mut i32;
 }
 
+#[clippy::msrv = "1.38"]
 fn _msrv_1_38() {
-    #![clippy::msrv = "1.38"]
     let ptr: *const u32 = &42_u32;
     let mut_ptr: *mut u32 = &mut 42_u32;
 
index ca2616b0069a07003d5d99e6505f0c86922b9e4c..302c66462d9b9e5ddd5f92f2d14ded1388cfe3ee 100644 (file)
@@ -2,7 +2,6 @@
 // aux-build:macro_rules.rs
 
 #![warn(clippy::ptr_as_ptr)]
-#![feature(custom_inner_attributes)]
 
 extern crate macro_rules;
 
@@ -45,8 +44,8 @@ fn main() {
     let _ = macro_rules::ptr_as_ptr_cast!(ptr);
 }
 
+#[clippy::msrv = "1.37"]
 fn _msrv_1_37() {
-    #![clippy::msrv = "1.37"]
     let ptr: *const u32 = &42_u32;
     let mut_ptr: *mut u32 = &mut 42_u32;
 
@@ -55,8 +54,8 @@ fn _msrv_1_37() {
     let _ = mut_ptr as *mut i32;
 }
 
+#[clippy::msrv = "1.38"]
 fn _msrv_1_38() {
-    #![clippy::msrv = "1.38"]
     let ptr: *const u32 = &42_u32;
     let mut_ptr: *mut u32 = &mut 42_u32;
 
index c58c55cfd83a15c5ac671f19f37ff4f64be212a8..a68e1cab6d357ecc6a2296287d643343bad2e42c 100644 (file)
@@ -1,5 +1,5 @@
 error: `as` casting between raw pointers without changing its mutability
-  --> $DIR/ptr_as_ptr.rs:19:13
+  --> $DIR/ptr_as_ptr.rs:18:13
    |
 LL |     let _ = ptr as *const i32;
    |             ^^^^^^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `ptr.cast::<i32>()`
@@ -7,31 +7,31 @@ LL |     let _ = ptr as *const i32;
    = note: `-D clippy::ptr-as-ptr` implied by `-D warnings`
 
 error: `as` casting between raw pointers without changing its mutability
-  --> $DIR/ptr_as_ptr.rs:20:13
+  --> $DIR/ptr_as_ptr.rs:19:13
    |
 LL |     let _ = mut_ptr as *mut i32;
    |             ^^^^^^^^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `mut_ptr.cast::<i32>()`
 
 error: `as` casting between raw pointers without changing its mutability
-  --> $DIR/ptr_as_ptr.rs:25:17
+  --> $DIR/ptr_as_ptr.rs:24:17
    |
 LL |         let _ = *ptr_ptr as *const i32;
    |                 ^^^^^^^^^^^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `(*ptr_ptr).cast::<i32>()`
 
 error: `as` casting between raw pointers without changing its mutability
-  --> $DIR/ptr_as_ptr.rs:38:25
+  --> $DIR/ptr_as_ptr.rs:37:25
    |
 LL |     let _: *const i32 = ptr as *const _;
    |                         ^^^^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `ptr.cast()`
 
 error: `as` casting between raw pointers without changing its mutability
-  --> $DIR/ptr_as_ptr.rs:39:23
+  --> $DIR/ptr_as_ptr.rs:38:23
    |
 LL |     let _: *mut i32 = mut_ptr as _;
    |                       ^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `mut_ptr.cast()`
 
 error: `as` casting between raw pointers without changing its mutability
-  --> $DIR/ptr_as_ptr.rs:11:9
+  --> $DIR/ptr_as_ptr.rs:10:9
    |
 LL |         $ptr as *const i32
    |         ^^^^^^^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `$ptr.cast::<i32>()`
@@ -42,13 +42,13 @@ LL |     let _ = cast_it!(ptr);
    = note: this error originates in the macro `cast_it` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: `as` casting between raw pointers without changing its mutability
-  --> $DIR/ptr_as_ptr.rs:63:13
+  --> $DIR/ptr_as_ptr.rs:62:13
    |
 LL |     let _ = ptr as *const i32;
    |             ^^^^^^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `ptr.cast::<i32>()`
 
 error: `as` casting between raw pointers without changing its mutability
-  --> $DIR/ptr_as_ptr.rs:64:13
+  --> $DIR/ptr_as_ptr.rs:63:13
    |
 LL |     let _ = mut_ptr as *mut i32;
    |             ^^^^^^^^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `mut_ptr.cast::<i32>()`
index 824f00cb99e85159987586450fc593ac93d97792..4923731fe45e8f8889f8e90ad5441e3ce81e0f4d 100644 (file)
@@ -1,6 +1,5 @@
 // run-rustfix
 
-#![feature(custom_inner_attributes)]
 #![warn(clippy::manual_range_contains)]
 #![allow(unused)]
 #![allow(clippy::no_effect)]
@@ -65,16 +64,14 @@ pub const fn in_range(a: i32) -> bool {
     3 <= a && a <= 20
 }
 
+#[clippy::msrv = "1.34"]
 fn msrv_1_34() {
-    #![clippy::msrv = "1.34"]
-
     let x = 5;
     x >= 8 && x < 34;
 }
 
+#[clippy::msrv = "1.35"]
 fn msrv_1_35() {
-    #![clippy::msrv = "1.35"]
-
     let x = 5;
     (8..35).contains(&x);
 }
index df925eeadfe5e0762f712412b29cf938de30ca08..d623ccb5da636fe71874883d0f4b9ed5f6147f08 100644 (file)
@@ -1,6 +1,5 @@
 // run-rustfix
 
-#![feature(custom_inner_attributes)]
 #![warn(clippy::manual_range_contains)]
 #![allow(unused)]
 #![allow(clippy::no_effect)]
@@ -65,16 +64,14 @@ pub const fn in_range(a: i32) -> bool {
     3 <= a && a <= 20
 }
 
+#[clippy::msrv = "1.34"]
 fn msrv_1_34() {
-    #![clippy::msrv = "1.34"]
-
     let x = 5;
     x >= 8 && x < 34;
 }
 
+#[clippy::msrv = "1.35"]
 fn msrv_1_35() {
-    #![clippy::msrv = "1.35"]
-
     let x = 5;
     x >= 8 && x < 35;
 }
index 9689e665b05c582ab061dc0734af45b461e0d059..ea34023a46645f14322dbf063b50e9139cd9c430 100644 (file)
@@ -1,5 +1,5 @@
 error: manual `Range::contains` implementation
-  --> $DIR/range_contains.rs:14:5
+  --> $DIR/range_contains.rs:13:5
    |
 LL |     x >= 8 && x < 12;
    |     ^^^^^^^^^^^^^^^^ help: use: `(8..12).contains(&x)`
@@ -7,121 +7,121 @@ LL |     x >= 8 && x < 12;
    = note: `-D clippy::manual-range-contains` implied by `-D warnings`
 
 error: manual `Range::contains` implementation
-  --> $DIR/range_contains.rs:15:5
+  --> $DIR/range_contains.rs:14:5
    |
 LL |     x < 42 && x >= 21;
    |     ^^^^^^^^^^^^^^^^^ help: use: `(21..42).contains(&x)`
 
 error: manual `Range::contains` implementation
-  --> $DIR/range_contains.rs:16:5
+  --> $DIR/range_contains.rs:15:5
    |
 LL |     100 > x && 1 <= x;
    |     ^^^^^^^^^^^^^^^^^ help: use: `(1..100).contains(&x)`
 
 error: manual `RangeInclusive::contains` implementation
-  --> $DIR/range_contains.rs:19:5
+  --> $DIR/range_contains.rs:18:5
    |
 LL |     x >= 9 && x <= 99;
    |     ^^^^^^^^^^^^^^^^^ help: use: `(9..=99).contains(&x)`
 
 error: manual `RangeInclusive::contains` implementation
-  --> $DIR/range_contains.rs:20:5
+  --> $DIR/range_contains.rs:19:5
    |
 LL |     x <= 33 && x >= 1;
    |     ^^^^^^^^^^^^^^^^^ help: use: `(1..=33).contains(&x)`
 
 error: manual `RangeInclusive::contains` implementation
-  --> $DIR/range_contains.rs:21:5
+  --> $DIR/range_contains.rs:20:5
    |
 LL |     999 >= x && 1 <= x;
    |     ^^^^^^^^^^^^^^^^^^ help: use: `(1..=999).contains(&x)`
 
 error: manual `!Range::contains` implementation
-  --> $DIR/range_contains.rs:24:5
+  --> $DIR/range_contains.rs:23:5
    |
 LL |     x < 8 || x >= 12;
    |     ^^^^^^^^^^^^^^^^ help: use: `!(8..12).contains(&x)`
 
 error: manual `!Range::contains` implementation
-  --> $DIR/range_contains.rs:25:5
+  --> $DIR/range_contains.rs:24:5
    |
 LL |     x >= 42 || x < 21;
    |     ^^^^^^^^^^^^^^^^^ help: use: `!(21..42).contains(&x)`
 
 error: manual `!Range::contains` implementation
-  --> $DIR/range_contains.rs:26:5
+  --> $DIR/range_contains.rs:25:5
    |
 LL |     100 <= x || 1 > x;
    |     ^^^^^^^^^^^^^^^^^ help: use: `!(1..100).contains(&x)`
 
 error: manual `!RangeInclusive::contains` implementation
-  --> $DIR/range_contains.rs:29:5
+  --> $DIR/range_contains.rs:28:5
    |
 LL |     x < 9 || x > 99;
    |     ^^^^^^^^^^^^^^^ help: use: `!(9..=99).contains(&x)`
 
 error: manual `!RangeInclusive::contains` implementation
-  --> $DIR/range_contains.rs:30:5
+  --> $DIR/range_contains.rs:29:5
    |
 LL |     x > 33 || x < 1;
    |     ^^^^^^^^^^^^^^^ help: use: `!(1..=33).contains(&x)`
 
 error: manual `!RangeInclusive::contains` implementation
-  --> $DIR/range_contains.rs:31:5
+  --> $DIR/range_contains.rs:30:5
    |
 LL |     999 < x || 1 > x;
    |     ^^^^^^^^^^^^^^^^ help: use: `!(1..=999).contains(&x)`
 
 error: manual `Range::contains` implementation
-  --> $DIR/range_contains.rs:46:5
+  --> $DIR/range_contains.rs:45:5
    |
 LL |     y >= 0. && y < 1.;
    |     ^^^^^^^^^^^^^^^^^ help: use: `(0. ..1.).contains(&y)`
 
 error: manual `!RangeInclusive::contains` implementation
-  --> $DIR/range_contains.rs:47:5
+  --> $DIR/range_contains.rs:46:5
    |
 LL |     y < 0. || y > 1.;
    |     ^^^^^^^^^^^^^^^^ help: use: `!(0. ..=1.).contains(&y)`
 
 error: manual `RangeInclusive::contains` implementation
-  --> $DIR/range_contains.rs:50:5
+  --> $DIR/range_contains.rs:49:5
    |
 LL |     x >= -10 && x <= 10;
    |     ^^^^^^^^^^^^^^^^^^^ help: use: `(-10..=10).contains(&x)`
 
 error: manual `RangeInclusive::contains` implementation
-  --> $DIR/range_contains.rs:52:5
+  --> $DIR/range_contains.rs:51:5
    |
 LL |     y >= -3. && y <= 3.;
    |     ^^^^^^^^^^^^^^^^^^^ help: use: `(-3. ..=3.).contains(&y)`
 
 error: manual `RangeInclusive::contains` implementation
-  --> $DIR/range_contains.rs:57:30
+  --> $DIR/range_contains.rs:56:30
    |
 LL |     (x >= 0) && (x <= 10) && (z >= 0) && (z <= 10);
    |                              ^^^^^^^^^^^^^^^^^^^^^ help: use: `(0..=10).contains(&z)`
 
 error: manual `RangeInclusive::contains` implementation
-  --> $DIR/range_contains.rs:57:5
+  --> $DIR/range_contains.rs:56:5
    |
 LL |     (x >= 0) && (x <= 10) && (z >= 0) && (z <= 10);
    |     ^^^^^^^^^^^^^^^^^^^^^ help: use: `(0..=10).contains(&x)`
 
 error: manual `!Range::contains` implementation
-  --> $DIR/range_contains.rs:58:29
+  --> $DIR/range_contains.rs:57:29
    |
 LL |     (x < 0) || (x >= 10) || (z < 0) || (z >= 10);
    |                             ^^^^^^^^^^^^^^^^^^^^ help: use: `!(0..10).contains(&z)`
 
 error: manual `!Range::contains` implementation
-  --> $DIR/range_contains.rs:58:5
+  --> $DIR/range_contains.rs:57:5
    |
 LL |     (x < 0) || (x >= 10) || (z < 0) || (z >= 10);
    |     ^^^^^^^^^^^^^^^^^^^^ help: use: `!(0..10).contains(&x)`
 
 error: manual `Range::contains` implementation
-  --> $DIR/range_contains.rs:79:5
+  --> $DIR/range_contains.rs:76:5
    |
 LL |     x >= 8 && x < 35;
    |     ^^^^^^^^^^^^^^^^ help: use: `(8..35).contains(&x)`
index 7cd687c95a003f14c770fed009c8c4062359156b..c0e49ff4caa7472f09bc38ce817b046f1cdb10a9 100644 (file)
@@ -25,4 +25,16 @@ fn main() {
         x * y
     };
     let d = async { something().await };
+
+    macro_rules! m {
+        () => {
+            0
+        };
+    }
+    macro_rules! m2 {
+        () => {
+            m!()
+        };
+    }
+    m2!();
 }
index 37e4d2238641576fbff1184315d1264d2741f205..9e6e54348a8c28f36f615a0444e86c59ef94b1f3 100644 (file)
@@ -25,4 +25,16 @@ fn main() {
         x * y
     })();
     let d = (async || something().await)();
+
+    macro_rules! m {
+        () => {
+            (|| 0)()
+        };
+    }
+    macro_rules! m2 {
+        () => {
+            (|| m!())()
+        };
+    }
+    m2!();
 }
index 56a8e57c0c362097b74fb1b000b1438a1c62b097..d71bcba2a8200414b0b74b98bb6c60a588f0e649 100644 (file)
@@ -52,5 +52,27 @@ error: try not to call a closure in the expression where it is declared
 LL |     let d = (async || something().await)();
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try doing something like: `async { something().await }`
 
-error: aborting due to 4 previous errors
+error: try not to call a closure in the expression where it is declared
+  --> $DIR/redundant_closure_call_fixable.rs:36:13
+   |
+LL |             (|| m!())()
+   |             ^^^^^^^^^^^ help: try doing something like: `m!()`
+...
+LL |     m2!();
+   |     ----- in this macro invocation
+   |
+   = note: this error originates in the macro `m2` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: try not to call a closure in the expression where it is declared
+  --> $DIR/redundant_closure_call_fixable.rs:31:13
+   |
+LL |             (|| 0)()
+   |             ^^^^^^^^ help: try doing something like: `0`
+...
+LL |     m2!();
+   |     ----- in this macro invocation
+   |
+   = note: this error originates in the macro `m` which comes from the expansion of the macro `m2` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to 6 previous errors
 
index 34ab552cb1d8d6aee22db40c07818a11eb42f8db..ec7f8ae923a793b3241715b68653b80f98180be6 100644 (file)
@@ -1,6 +1,5 @@
 // run-rustfix
 
-#![feature(custom_inner_attributes)]
 #![warn(clippy::redundant_field_names)]
 #![allow(clippy::no_effect, dead_code, unused_variables)]
 
@@ -72,16 +71,14 @@ fn issue_3476() {
     S { foo: foo::<i32> };
 }
 
+#[clippy::msrv = "1.16"]
 fn msrv_1_16() {
-    #![clippy::msrv = "1.16"]
-
     let start = 0;
     let _ = RangeFrom { start: start };
 }
 
+#[clippy::msrv = "1.17"]
 fn msrv_1_17() {
-    #![clippy::msrv = "1.17"]
-
     let start = 0;
     let _ = RangeFrom { start };
 }
index a051b1f96f0fda8dad22fe3fba5f867d0249263a..73122016cf69e9eefec777cde172735926f503ee 100644 (file)
@@ -1,6 +1,5 @@
 // run-rustfix
 
-#![feature(custom_inner_attributes)]
 #![warn(clippy::redundant_field_names)]
 #![allow(clippy::no_effect, dead_code, unused_variables)]
 
@@ -72,16 +71,14 @@ struct S {
     S { foo: foo::<i32> };
 }
 
+#[clippy::msrv = "1.16"]
 fn msrv_1_16() {
-    #![clippy::msrv = "1.16"]
-
     let start = 0;
     let _ = RangeFrom { start: start };
 }
 
+#[clippy::msrv = "1.17"]
 fn msrv_1_17() {
-    #![clippy::msrv = "1.17"]
-
     let start = 0;
     let _ = RangeFrom { start: start };
 }
index 8b82e062b93a63325c94f5e4c79b5f9592f63f5c..00a72c50cf7d0324cc3600fc069cc333d9158594 100644 (file)
@@ -1,5 +1,5 @@
 error: redundant field names in struct initialization
-  --> $DIR/redundant_field_names.rs:36:9
+  --> $DIR/redundant_field_names.rs:35:9
    |
 LL |         gender: gender,
    |         ^^^^^^^^^^^^^^ help: replace it with: `gender`
@@ -7,43 +7,43 @@ LL |         gender: gender,
    = note: `-D clippy::redundant-field-names` implied by `-D warnings`
 
 error: redundant field names in struct initialization
-  --> $DIR/redundant_field_names.rs:37:9
+  --> $DIR/redundant_field_names.rs:36:9
    |
 LL |         age: age,
    |         ^^^^^^^^ help: replace it with: `age`
 
 error: redundant field names in struct initialization
-  --> $DIR/redundant_field_names.rs:58:25
+  --> $DIR/redundant_field_names.rs:57:25
    |
 LL |     let _ = RangeFrom { start: start };
    |                         ^^^^^^^^^^^^ help: replace it with: `start`
 
 error: redundant field names in struct initialization
-  --> $DIR/redundant_field_names.rs:59:23
+  --> $DIR/redundant_field_names.rs:58:23
    |
 LL |     let _ = RangeTo { end: end };
    |                       ^^^^^^^^ help: replace it with: `end`
 
 error: redundant field names in struct initialization
-  --> $DIR/redundant_field_names.rs:60:21
+  --> $DIR/redundant_field_names.rs:59:21
    |
 LL |     let _ = Range { start: start, end: end };
    |                     ^^^^^^^^^^^^ help: replace it with: `start`
 
 error: redundant field names in struct initialization
-  --> $DIR/redundant_field_names.rs:60:35
+  --> $DIR/redundant_field_names.rs:59:35
    |
 LL |     let _ = Range { start: start, end: end };
    |                                   ^^^^^^^^ help: replace it with: `end`
 
 error: redundant field names in struct initialization
-  --> $DIR/redundant_field_names.rs:62:32
+  --> $DIR/redundant_field_names.rs:61:32
    |
 LL |     let _ = RangeToInclusive { end: end };
    |                                ^^^^^^^^ help: replace it with: `end`
 
 error: redundant field names in struct initialization
-  --> $DIR/redundant_field_names.rs:86:25
+  --> $DIR/redundant_field_names.rs:83:25
    |
 LL |     let _ = RangeFrom { start: start };
    |                         ^^^^^^^^^^^^ help: replace it with: `start`
index 42110dbe81e84f8d35f678b7613be06f4b2f9a53..4c5846fe837eaa8a68ed10ad585271923f0f6588 100644 (file)
@@ -1,6 +1,5 @@
 // run-rustfix
 
-#![feature(custom_inner_attributes)]
 #![allow(unused)]
 
 #[derive(Debug)]
@@ -56,14 +55,12 @@ impl Bar for Foo {
     const TRAIT_VAR: &'static str = "foo";
 }
 
+#[clippy::msrv = "1.16"]
 fn msrv_1_16() {
-    #![clippy::msrv = "1.16"]
-
     static V: &'static u8 = &16;
 }
 
+#[clippy::msrv = "1.17"]
 fn msrv_1_17() {
-    #![clippy::msrv = "1.17"]
-
     static V: &u8 = &17;
 }
index bc5200bc8625b0a200e05035f2582f3dd2eab21d..64a66be1a83c753ff8a786167759fd4f04ea52ef 100644 (file)
@@ -1,6 +1,5 @@
 // run-rustfix
 
-#![feature(custom_inner_attributes)]
 #![allow(unused)]
 
 #[derive(Debug)]
@@ -56,14 +55,12 @@ impl Bar for Foo {
     const TRAIT_VAR: &'static str = "foo";
 }
 
+#[clippy::msrv = "1.16"]
 fn msrv_1_16() {
-    #![clippy::msrv = "1.16"]
-
     static V: &'static u8 = &16;
 }
 
+#[clippy::msrv = "1.17"]
 fn msrv_1_17() {
-    #![clippy::msrv = "1.17"]
-
     static V: &'static u8 = &17;
 }
index 735113460d28caf9c67ea003d651fe7cbf9fbafc..0938ebf783ff16888852e0be386dc22c86f1c254 100644 (file)
@@ -1,5 +1,5 @@
 error: constants have by default a `'static` lifetime
-  --> $DIR/redundant_static_lifetimes.rs:9:17
+  --> $DIR/redundant_static_lifetimes.rs:8:17
    |
 LL | const VAR_ONE: &'static str = "Test constant #1"; // ERROR Consider removing 'static.
    |                -^^^^^^^---- help: consider removing `'static`: `&str`
@@ -7,97 +7,97 @@ LL | const VAR_ONE: &'static str = "Test constant #1"; // ERROR Consider removin
    = note: `-D clippy::redundant-static-lifetimes` implied by `-D warnings`
 
 error: constants have by default a `'static` lifetime
-  --> $DIR/redundant_static_lifetimes.rs:13:21
+  --> $DIR/redundant_static_lifetimes.rs:12:21
    |
 LL | const VAR_THREE: &[&'static str] = &["one", "two"]; // ERROR Consider removing 'static
    |                    -^^^^^^^---- help: consider removing `'static`: `&str`
 
 error: constants have by default a `'static` lifetime
-  --> $DIR/redundant_static_lifetimes.rs:15:32
+  --> $DIR/redundant_static_lifetimes.rs:14:32
    |
 LL | const VAR_FOUR: (&str, (&str, &'static str), &'static str) = ("on", ("th", "th"), "on"); // ERROR Consider removing 'static
    |                               -^^^^^^^---- help: consider removing `'static`: `&str`
 
 error: constants have by default a `'static` lifetime
-  --> $DIR/redundant_static_lifetimes.rs:15:47
+  --> $DIR/redundant_static_lifetimes.rs:14:47
    |
 LL | const VAR_FOUR: (&str, (&str, &'static str), &'static str) = ("on", ("th", "th"), "on"); // ERROR Consider removing 'static
    |                                              -^^^^^^^---- help: consider removing `'static`: `&str`
 
 error: constants have by default a `'static` lifetime
-  --> $DIR/redundant_static_lifetimes.rs:17:17
+  --> $DIR/redundant_static_lifetimes.rs:16:17
    |
 LL | const VAR_SIX: &'static u8 = &5;
    |                -^^^^^^^--- help: consider removing `'static`: `&u8`
 
 error: constants have by default a `'static` lifetime
-  --> $DIR/redundant_static_lifetimes.rs:19:20
+  --> $DIR/redundant_static_lifetimes.rs:18:20
    |
 LL | const VAR_HEIGHT: &'static Foo = &Foo {};
    |                   -^^^^^^^---- help: consider removing `'static`: `&Foo`
 
 error: constants have by default a `'static` lifetime
-  --> $DIR/redundant_static_lifetimes.rs:21:19
+  --> $DIR/redundant_static_lifetimes.rs:20:19
    |
 LL | const VAR_SLICE: &'static [u8] = b"Test constant #1"; // ERROR Consider removing 'static.
    |                  -^^^^^^^----- help: consider removing `'static`: `&[u8]`
 
 error: constants have by default a `'static` lifetime
-  --> $DIR/redundant_static_lifetimes.rs:23:19
+  --> $DIR/redundant_static_lifetimes.rs:22:19
    |
 LL | const VAR_TUPLE: &'static (u8, u8) = &(1, 2); // ERROR Consider removing 'static.
    |                  -^^^^^^^--------- help: consider removing `'static`: `&(u8, u8)`
 
 error: constants have by default a `'static` lifetime
-  --> $DIR/redundant_static_lifetimes.rs:25:19
+  --> $DIR/redundant_static_lifetimes.rs:24:19
    |
 LL | const VAR_ARRAY: &'static [u8; 1] = b"T"; // ERROR Consider removing 'static.
    |                  -^^^^^^^-------- help: consider removing `'static`: `&[u8; 1]`
 
 error: statics have by default a `'static` lifetime
-  --> $DIR/redundant_static_lifetimes.rs:27:25
+  --> $DIR/redundant_static_lifetimes.rs:26:25
    |
 LL | static STATIC_VAR_ONE: &'static str = "Test static #1"; // ERROR Consider removing 'static.
    |                        -^^^^^^^---- help: consider removing `'static`: `&str`
 
 error: statics have by default a `'static` lifetime
-  --> $DIR/redundant_static_lifetimes.rs:31:29
+  --> $DIR/redundant_static_lifetimes.rs:30:29
    |
 LL | static STATIC_VAR_THREE: &[&'static str] = &["one", "two"]; // ERROR Consider removing 'static
    |                            -^^^^^^^---- help: consider removing `'static`: `&str`
 
 error: statics have by default a `'static` lifetime
-  --> $DIR/redundant_static_lifetimes.rs:33:25
+  --> $DIR/redundant_static_lifetimes.rs:32:25
    |
 LL | static STATIC_VAR_SIX: &'static u8 = &5;
    |                        -^^^^^^^--- help: consider removing `'static`: `&u8`
 
 error: statics have by default a `'static` lifetime
-  --> $DIR/redundant_static_lifetimes.rs:35:28
+  --> $DIR/redundant_static_lifetimes.rs:34:28
    |
 LL | static STATIC_VAR_HEIGHT: &'static Foo = &Foo {};
    |                           -^^^^^^^---- help: consider removing `'static`: `&Foo`
 
 error: statics have by default a `'static` lifetime
-  --> $DIR/redundant_static_lifetimes.rs:37:27
+  --> $DIR/redundant_static_lifetimes.rs:36:27
    |
 LL | static STATIC_VAR_SLICE: &'static [u8] = b"Test static #3"; // ERROR Consider removing 'static.
    |                          -^^^^^^^----- help: consider removing `'static`: `&[u8]`
 
 error: statics have by default a `'static` lifetime
-  --> $DIR/redundant_static_lifetimes.rs:39:27
+  --> $DIR/redundant_static_lifetimes.rs:38:27
    |
 LL | static STATIC_VAR_TUPLE: &'static (u8, u8) = &(1, 2); // ERROR Consider removing 'static.
    |                          -^^^^^^^--------- help: consider removing `'static`: `&(u8, u8)`
 
 error: statics have by default a `'static` lifetime
-  --> $DIR/redundant_static_lifetimes.rs:41:27
+  --> $DIR/redundant_static_lifetimes.rs:40:27
    |
 LL | static STATIC_VAR_ARRAY: &'static [u8; 1] = b"T"; // ERROR Consider removing 'static.
    |                          -^^^^^^^-------- help: consider removing `'static`: `&[u8; 1]`
 
 error: statics have by default a `'static` lifetime
-  --> $DIR/redundant_static_lifetimes.rs:68:16
+  --> $DIR/redundant_static_lifetimes.rs:65:16
    |
 LL |     static V: &'static u8 = &17;
    |               -^^^^^^^--- help: consider removing `'static`: `&u8`
index 9dd27d6dc01aaf8ae40245fc024c49b0e35cea14..1c12cebfd971a372480593586f63c009d5940978 100644 (file)
@@ -108,4 +108,10 @@ pub fn array_error<T, U>() -> Result<(), ArrayError<(i32, T), U>> {
     Ok(())
 }
 
+// Issue #10005
+enum Empty {}
+fn _empty_error() -> Result<(), Empty> {
+    Ok(())
+}
+
 fn main() {}
index 4b5303324bc6f17e7dde1e1dc477c1eac2b3c357..1309c91b81c9830b52f9813d1bf0d75b572251e3 100644 (file)
@@ -1,12 +1,11 @@
 // run-rustfix
 #![warn(clippy::seek_from_current)]
-#![feature(custom_inner_attributes)]
 
 use std::fs::File;
 use std::io::{self, Seek, SeekFrom, Write};
 
+#[clippy::msrv = "1.50"]
 fn _msrv_1_50() -> io::Result<()> {
-    #![clippy::msrv = "1.50"]
     let mut f = File::create("foo.txt")?;
     f.write_all(b"Hi!")?;
     f.seek(SeekFrom::Current(0))?;
@@ -14,8 +13,8 @@ fn _msrv_1_50() -> io::Result<()> {
     Ok(())
 }
 
+#[clippy::msrv = "1.51"]
 fn _msrv_1_51() -> io::Result<()> {
-    #![clippy::msrv = "1.51"]
     let mut f = File::create("foo.txt")?;
     f.write_all(b"Hi!")?;
     f.stream_position()?;
index f93639261a1808241f7e24dfc1957c4c71c1907e..5d9b1424cf686fe5bd1ec150b86c7e8d6a7f0d3a 100644 (file)
@@ -1,12 +1,11 @@
 // run-rustfix
 #![warn(clippy::seek_from_current)]
-#![feature(custom_inner_attributes)]
 
 use std::fs::File;
 use std::io::{self, Seek, SeekFrom, Write};
 
+#[clippy::msrv = "1.50"]
 fn _msrv_1_50() -> io::Result<()> {
-    #![clippy::msrv = "1.50"]
     let mut f = File::create("foo.txt")?;
     f.write_all(b"Hi!")?;
     f.seek(SeekFrom::Current(0))?;
@@ -14,8 +13,8 @@ fn _msrv_1_50() -> io::Result<()> {
     Ok(())
 }
 
+#[clippy::msrv = "1.51"]
 fn _msrv_1_51() -> io::Result<()> {
-    #![clippy::msrv = "1.51"]
     let mut f = File::create("foo.txt")?;
     f.write_all(b"Hi!")?;
     f.seek(SeekFrom::Current(0))?;
index db1125b53cdf5c2182970a9c748633f0d9c5840d..c079f361192928bcea5fe74a99da5e93cc521309 100644 (file)
@@ -1,5 +1,5 @@
 error: using `SeekFrom::Current` to start from current position
-  --> $DIR/seek_from_current.rs:21:5
+  --> $DIR/seek_from_current.rs:20:5
    |
 LL |     f.seek(SeekFrom::Current(0))?;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `f.stream_position()`
index 464b6cdef63933acde79d463929e163049252bd8..9d0d1124c460ed45b1b5894bd3878b18d15def72 100644 (file)
@@ -1,6 +1,5 @@
 // run-rustfix
 #![allow(unused)]
-#![feature(custom_inner_attributes)]
 #![warn(clippy::seek_to_start_instead_of_rewind)]
 
 use std::fs::OpenOptions;
@@ -94,9 +93,8 @@ fn main() {
     assert_eq!(&buf, hello);
 }
 
+#[clippy::msrv = "1.54"]
 fn msrv_1_54() {
-    #![clippy::msrv = "1.54"]
-
     let mut f = OpenOptions::new()
         .write(true)
         .read(true)
@@ -115,9 +113,8 @@ fn msrv_1_54() {
     assert_eq!(&buf, hello);
 }
 
+#[clippy::msrv = "1.55"]
 fn msrv_1_55() {
-    #![clippy::msrv = "1.55"]
-
     let mut f = OpenOptions::new()
         .write(true)
         .read(true)
index 68e09bd7c1f0fd4d4d210e90b58e50b04c1a1d40..c5bc57cc3a74ce617a96b4dd401a58cca895647b 100644 (file)
@@ -1,6 +1,5 @@
 // run-rustfix
 #![allow(unused)]
-#![feature(custom_inner_attributes)]
 #![warn(clippy::seek_to_start_instead_of_rewind)]
 
 use std::fs::OpenOptions;
@@ -94,9 +93,8 @@ fn main() {
     assert_eq!(&buf, hello);
 }
 
+#[clippy::msrv = "1.54"]
 fn msrv_1_54() {
-    #![clippy::msrv = "1.54"]
-
     let mut f = OpenOptions::new()
         .write(true)
         .read(true)
@@ -115,9 +113,8 @@ fn msrv_1_54() {
     assert_eq!(&buf, hello);
 }
 
+#[clippy::msrv = "1.55"]
 fn msrv_1_55() {
-    #![clippy::msrv = "1.55"]
-
     let mut f = OpenOptions::new()
         .write(true)
         .read(true)
index de0eec5d909cd72695def70bc63abee7eecea714..6cce025359fe2918bce42ea6bdbef601d8c74948 100644 (file)
@@ -1,5 +1,5 @@
 error: used `seek` to go to the start of the stream
-  --> $DIR/seek_to_start_instead_of_rewind.rs:54:7
+  --> $DIR/seek_to_start_instead_of_rewind.rs:53:7
    |
 LL |     t.seek(SeekFrom::Start(0));
    |       ^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `rewind()`
@@ -7,13 +7,13 @@ LL |     t.seek(SeekFrom::Start(0));
    = note: `-D clippy::seek-to-start-instead-of-rewind` implied by `-D warnings`
 
 error: used `seek` to go to the start of the stream
-  --> $DIR/seek_to_start_instead_of_rewind.rs:59:7
+  --> $DIR/seek_to_start_instead_of_rewind.rs:58:7
    |
 LL |     t.seek(SeekFrom::Start(0));
    |       ^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `rewind()`
 
 error: used `seek` to go to the start of the stream
-  --> $DIR/seek_to_start_instead_of_rewind.rs:131:7
+  --> $DIR/seek_to_start_instead_of_rewind.rs:128:7
    |
 LL |     f.seek(SeekFrom::Start(0));
    |       ^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `rewind()`
index e5fe9133f975eebc1e6d6ff3821cecd36ba5480a..074dae5fb2868bf1906f523e3c9aa0b222427eb3 100644 (file)
@@ -1,6 +1,5 @@
 // run-rustfix
 
-#![feature(custom_inner_attributes)]
 #![warn(clippy::transmute_ptr_to_ref)]
 #![allow(clippy::match_single_binding)]
 
@@ -51,8 +50,8 @@ unsafe fn _issue8924<'a, 'b, 'c>(x: *const &'a u32, y: *const &'b u32) -> &'c &'
     }
 }
 
+#[clippy::msrv = "1.38"]
 unsafe fn _meets_msrv<'a, 'b, 'c>(x: *const &'a u32) -> &'c &'b u32 {
-    #![clippy::msrv = "1.38"]
     let a = 0u32;
     let a = &a as *const u32;
     let _: &u32 = &*a;
@@ -63,8 +62,8 @@ unsafe fn _meets_msrv<'a, 'b, 'c>(x: *const &'a u32) -> &'c &'b u32 {
     }
 }
 
+#[clippy::msrv = "1.37"]
 unsafe fn _under_msrv<'a, 'b, 'c>(x: *const &'a u32) -> &'c &'b u32 {
-    #![clippy::msrv = "1.37"]
     let a = 0u32;
     let a = &a as *const u32;
     let _: &u32 = &*a;
index fe49cdc324fdd397e3db32cf85f46338753ae702..2edc122cf47127b1b8e364f3ce4409e72d209855 100644 (file)
@@ -1,6 +1,5 @@
 // run-rustfix
 
-#![feature(custom_inner_attributes)]
 #![warn(clippy::transmute_ptr_to_ref)]
 #![allow(clippy::match_single_binding)]
 
@@ -51,8 +50,8 @@ unsafe fn _issue8924<'a, 'b, 'c>(x: *const &'a u32, y: *const &'b u32) -> &'c &'
     }
 }
 
+#[clippy::msrv = "1.38"]
 unsafe fn _meets_msrv<'a, 'b, 'c>(x: *const &'a u32) -> &'c &'b u32 {
-    #![clippy::msrv = "1.38"]
     let a = 0u32;
     let a = &a as *const u32;
     let _: &u32 = std::mem::transmute(a);
@@ -63,8 +62,8 @@ unsafe fn _meets_msrv<'a, 'b, 'c>(x: *const &'a u32) -> &'c &'b u32 {
     }
 }
 
+#[clippy::msrv = "1.37"]
 unsafe fn _under_msrv<'a, 'b, 'c>(x: *const &'a u32) -> &'c &'b u32 {
-    #![clippy::msrv = "1.37"]
     let a = 0u32;
     let a = &a as *const u32;
     let _: &u32 = std::mem::transmute(a);
index 10117ee9182ab97d97e9bb13e5cee991a399980f..b3e6c09d2d7a1f2882996aa36818067edec35586 100644 (file)
@@ -1,5 +1,5 @@
 error: transmute from a pointer type (`*const T`) to a reference type (`&T`)
-  --> $DIR/transmute_ptr_to_ref.rs:8:17
+  --> $DIR/transmute_ptr_to_ref.rs:7:17
    |
 LL |     let _: &T = std::mem::transmute(p);
    |                 ^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*p`
@@ -7,127 +7,127 @@ LL |     let _: &T = std::mem::transmute(p);
    = note: `-D clippy::transmute-ptr-to-ref` implied by `-D warnings`
 
 error: transmute from a pointer type (`*mut T`) to a reference type (`&mut T`)
-  --> $DIR/transmute_ptr_to_ref.rs:11:21
+  --> $DIR/transmute_ptr_to_ref.rs:10:21
    |
 LL |     let _: &mut T = std::mem::transmute(m);
    |                     ^^^^^^^^^^^^^^^^^^^^^^ help: try: `&mut *m`
 
 error: transmute from a pointer type (`*mut T`) to a reference type (`&T`)
-  --> $DIR/transmute_ptr_to_ref.rs:14:17
+  --> $DIR/transmute_ptr_to_ref.rs:13:17
    |
 LL |     let _: &T = std::mem::transmute(m);
    |                 ^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*m`
 
 error: transmute from a pointer type (`*mut T`) to a reference type (`&mut T`)
-  --> $DIR/transmute_ptr_to_ref.rs:17:21
+  --> $DIR/transmute_ptr_to_ref.rs:16:21
    |
 LL |     let _: &mut T = std::mem::transmute(p as *mut T);
    |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&mut *(p as *mut T)`
 
 error: transmute from a pointer type (`*const U`) to a reference type (`&T`)
-  --> $DIR/transmute_ptr_to_ref.rs:20:17
+  --> $DIR/transmute_ptr_to_ref.rs:19:17
    |
 LL |     let _: &T = std::mem::transmute(o);
    |                 ^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(o as *const T)`
 
 error: transmute from a pointer type (`*mut U`) to a reference type (`&mut T`)
-  --> $DIR/transmute_ptr_to_ref.rs:23:21
+  --> $DIR/transmute_ptr_to_ref.rs:22:21
    |
 LL |     let _: &mut T = std::mem::transmute(om);
    |                     ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&mut *(om as *mut T)`
 
 error: transmute from a pointer type (`*mut U`) to a reference type (`&T`)
-  --> $DIR/transmute_ptr_to_ref.rs:26:17
+  --> $DIR/transmute_ptr_to_ref.rs:25:17
    |
 LL |     let _: &T = std::mem::transmute(om);
    |                 ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(om as *const T)`
 
 error: transmute from a pointer type (`*const i32`) to a reference type (`&_issue1231::Foo<'_, u8>`)
-  --> $DIR/transmute_ptr_to_ref.rs:36:32
+  --> $DIR/transmute_ptr_to_ref.rs:35:32
    |
 LL |     let _: &Foo<u8> = unsafe { std::mem::transmute::<_, &Foo<_>>(raw) };
    |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*raw.cast::<Foo<_>>()`
 
 error: transmute from a pointer type (`*const i32`) to a reference type (`&_issue1231::Foo<'_, &u8>`)
-  --> $DIR/transmute_ptr_to_ref.rs:38:33
+  --> $DIR/transmute_ptr_to_ref.rs:37:33
    |
 LL |     let _: &Foo<&u8> = unsafe { std::mem::transmute::<_, &Foo<&_>>(raw) };
    |                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*raw.cast::<Foo<&_>>()`
 
 error: transmute from a pointer type (`*const i32`) to a reference type (`&u8`)
-  --> $DIR/transmute_ptr_to_ref.rs:42:14
+  --> $DIR/transmute_ptr_to_ref.rs:41:14
    |
 LL |     unsafe { std::mem::transmute::<_, Bar>(raw) };
    |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(raw as *const u8)`
 
 error: transmute from a pointer type (`*const &u32`) to a reference type (`&&u32`)
-  --> $DIR/transmute_ptr_to_ref.rs:47:14
+  --> $DIR/transmute_ptr_to_ref.rs:46:14
    |
 LL |         0 => std::mem::transmute(x),
    |              ^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*x.cast::<&u32>()`
 
 error: transmute from a pointer type (`*const &u32`) to a reference type (`&&u32`)
-  --> $DIR/transmute_ptr_to_ref.rs:48:14
+  --> $DIR/transmute_ptr_to_ref.rs:47:14
    |
 LL |         1 => std::mem::transmute(y),
    |              ^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*y.cast::<&u32>()`
 
 error: transmute from a pointer type (`*const &u32`) to a reference type (`&&u32`)
-  --> $DIR/transmute_ptr_to_ref.rs:49:14
+  --> $DIR/transmute_ptr_to_ref.rs:48:14
    |
 LL |         2 => std::mem::transmute::<_, &&'b u32>(x),
    |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*x.cast::<&'b u32>()`
 
 error: transmute from a pointer type (`*const &u32`) to a reference type (`&&u32`)
-  --> $DIR/transmute_ptr_to_ref.rs:50:14
+  --> $DIR/transmute_ptr_to_ref.rs:49:14
    |
 LL |         _ => std::mem::transmute::<_, &&'b u32>(y),
    |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*y.cast::<&'b u32>()`
 
 error: transmute from a pointer type (`*const u32`) to a reference type (`&u32`)
-  --> $DIR/transmute_ptr_to_ref.rs:58:19
+  --> $DIR/transmute_ptr_to_ref.rs:57:19
    |
 LL |     let _: &u32 = std::mem::transmute(a);
    |                   ^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*a`
 
 error: transmute from a pointer type (`*const u32`) to a reference type (`&u32`)
-  --> $DIR/transmute_ptr_to_ref.rs:59:19
+  --> $DIR/transmute_ptr_to_ref.rs:58:19
    |
 LL |     let _: &u32 = std::mem::transmute::<_, &u32>(a);
    |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*a.cast::<u32>()`
 
 error: transmute from a pointer type (`*const &u32`) to a reference type (`&&u32`)
-  --> $DIR/transmute_ptr_to_ref.rs:61:14
+  --> $DIR/transmute_ptr_to_ref.rs:60:14
    |
 LL |         0 => std::mem::transmute(x),
    |              ^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*x.cast::<&u32>()`
 
 error: transmute from a pointer type (`*const &u32`) to a reference type (`&&u32`)
-  --> $DIR/transmute_ptr_to_ref.rs:62:14
+  --> $DIR/transmute_ptr_to_ref.rs:61:14
    |
 LL |         _ => std::mem::transmute::<_, &&'b u32>(x),
    |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*x.cast::<&'b u32>()`
 
 error: transmute from a pointer type (`*const u32`) to a reference type (`&u32`)
-  --> $DIR/transmute_ptr_to_ref.rs:70:19
+  --> $DIR/transmute_ptr_to_ref.rs:69:19
    |
 LL |     let _: &u32 = std::mem::transmute(a);
    |                   ^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*a`
 
 error: transmute from a pointer type (`*const u32`) to a reference type (`&u32`)
-  --> $DIR/transmute_ptr_to_ref.rs:71:19
+  --> $DIR/transmute_ptr_to_ref.rs:70:19
    |
 LL |     let _: &u32 = std::mem::transmute::<_, &u32>(a);
    |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(a as *const u32)`
 
 error: transmute from a pointer type (`*const &u32`) to a reference type (`&&u32`)
-  --> $DIR/transmute_ptr_to_ref.rs:73:14
+  --> $DIR/transmute_ptr_to_ref.rs:72:14
    |
 LL |         0 => std::mem::transmute(x),
    |              ^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(x as *const () as *const &u32)`
 
 error: transmute from a pointer type (`*const &u32`) to a reference type (`&&u32`)
-  --> $DIR/transmute_ptr_to_ref.rs:74:14
+  --> $DIR/transmute_ptr_to_ref.rs:73:14
    |
 LL |         _ => std::mem::transmute::<_, &&'b u32>(x),
    |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(x as *const () as *const &'b u32)`
index cbc6768033ec822bb7b4bfe6447579585a85000d..c05eb447b2ebd34e50ef3db1197116eab83e7241 100644 (file)
@@ -1,6 +1,6 @@
 // aux-build:proc_macro_unsafe.rs
 
-#![warn(clippy::undocumented_unsafe_blocks)]
+#![warn(clippy::undocumented_unsafe_blocks, clippy::unnecessary_safety_comment)]
 #![allow(clippy::let_unit_value, clippy::missing_safety_doc)]
 
 extern crate proc_macro_unsafe;
index ba4de9806d17523a4675a4d9250b7fe94695dfc9..d1c1bb5ffeac85eec808031e3f97ad96d82b8425 100644 (file)
@@ -239,6 +239,19 @@ LL |     unsafe impl TrailingComment for () {} // SAFETY:
    |
    = help: consider adding a safety comment on the preceding line
 
+error: constant item has unnecessary safety comment
+  --> $DIR/undocumented_unsafe_blocks.rs:471:5
+   |
+LL |     const BIG_NUMBER: i32 = 1000000;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: consider removing the safety comment
+  --> $DIR/undocumented_unsafe_blocks.rs:470:5
+   |
+LL |     // SAFETY:
+   |     ^^^^^^^^^^
+   = note: `-D clippy::unnecessary-safety-comment` implied by `-D warnings`
+
 error: unsafe impl missing a safety comment
   --> $DIR/undocumented_unsafe_blocks.rs:472:5
    |
@@ -271,6 +284,24 @@ LL |         unsafe {};
    |
    = help: consider adding a safety comment on the preceding line
 
+error: statement has unnecessary safety comment
+  --> $DIR/undocumented_unsafe_blocks.rs:501:5
+   |
+LL | /     let _ = {
+LL | |         if unsafe { true } {
+LL | |             todo!();
+LL | |         } else {
+...  |
+LL | |         }
+LL | |     };
+   | |______^
+   |
+help: consider removing the safety comment
+  --> $DIR/undocumented_unsafe_blocks.rs:500:5
+   |
+LL |     // SAFETY: this is more than one level away, so it should warn
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
 error: unsafe block missing a safety comment
   --> $DIR/undocumented_unsafe_blocks.rs:502:12
    |
@@ -287,5 +318,5 @@ LL |             let bar = unsafe {};
    |
    = help: consider adding a safety comment on the preceding line
 
-error: aborting due to 34 previous errors
+error: aborting due to 36 previous errors
 
index 106274479751d7439a50bc2411b9106317447f3b..9d08e80cf9a55717b7ccb7b3fd137d4a3b9b5178 100644 (file)
@@ -1,6 +1,5 @@
 // aux-build:proc_macro_with_span.rs
 // run-rustfix
-#![feature(custom_inner_attributes)]
 #![warn(clippy::uninlined_format_args)]
 #![allow(named_arguments_used_positionally, unused_imports, unused_macros, unused_variables)]
 #![allow(clippy::eq_op, clippy::format_in_format_args, clippy::print_literal)]
@@ -44,9 +43,7 @@ fn tester(fn_arg: i32) {
     println!("val='{local_i32}'"); // space+tab
     println!("val='{local_i32}'"); // tab+space
     println!(
-        "val='{
-    }'",
-        local_i32
+        "val='{local_i32}'"
     );
     println!("{local_i32}");
     println!("{fn_arg}");
@@ -57,11 +54,11 @@ fn tester(fn_arg: i32) {
     println!("{local_i32:<3}");
     println!("{local_i32:#010x}");
     println!("{local_f64:.1}");
-    println!("Hello {} is {local_f64:.local_i32$}", "x");
-    println!("Hello {local_i32} is {local_f64:.*}", 5);
-    println!("Hello {local_i32} is {local_f64:.*}", 5);
+    println!("Hello {} is {:.*}", "x", local_i32, local_f64);
+    println!("Hello {} is {:.*}", local_i32, 5, local_f64);
+    println!("Hello {} is {2:.*}", local_i32, 5, local_f64);
     println!("{local_i32} {local_f64}");
-    println!("{local_i32}, {}", local_opt.unwrap());
+    println!("{}, {}", local_i32, local_opt.unwrap());
     println!("{val}");
     println!("{val}");
     println!("{} {1}", local_i32, 42);
@@ -110,8 +107,7 @@ fn tester(fn_arg: i32) {
     println!("{local_f64:width$.prec$}");
     println!("{local_f64:width$.prec$} {local_f64} {width} {prec}");
     println!(
-        "{0:1$.2$} {0:2$.1$} {1:0$.2$} {1:2$.0$} {2:0$.1$} {2:1$.0$}",
-        local_i32, width, prec,
+        "{local_i32:width$.prec$} {local_i32:prec$.width$} {width:local_i32$.prec$} {width:prec$.local_i32$} {prec:local_i32$.width$} {prec:width$.local_i32$}",
     );
     println!(
         "{0:1$.2$} {0:2$.1$} {1:0$.2$} {1:2$.0$} {2:0$.1$} {2:1$.0$} {3}",
@@ -142,9 +138,7 @@ fn tester(fn_arg: i32) {
     println!(no_param_str!(), local_i32);
 
     println!(
-        "{}",
-        // comment with a comma , in it
-        val,
+        "{val}",
     );
     println!("{val}");
 
@@ -169,14 +163,14 @@ fn main() {
     tester(42);
 }
 
+#[clippy::msrv = "1.57"]
 fn _under_msrv() {
-    #![clippy::msrv = "1.57"]
     let local_i32 = 1;
     println!("don't expand='{}'", local_i32);
 }
 
+#[clippy::msrv = "1.58"]
 fn _meets_msrv() {
-    #![clippy::msrv = "1.58"]
     let local_i32 = 1;
     println!("expand='{local_i32}'");
 }
index 8e495ebd083a55e6eacae4ba91dbc7859c5d2ec6..35b3677a8968ffe480a4fafcf62adc979c1e17b7 100644 (file)
@@ -1,6 +1,5 @@
 // aux-build:proc_macro_with_span.rs
 // run-rustfix
-#![feature(custom_inner_attributes)]
 #![warn(clippy::uninlined_format_args)]
 #![allow(named_arguments_used_positionally, unused_imports, unused_macros, unused_variables)]
 #![allow(clippy::eq_op, clippy::format_in_format_args, clippy::print_literal)]
@@ -169,14 +168,14 @@ fn main() {
     tester(42);
 }
 
+#[clippy::msrv = "1.57"]
 fn _under_msrv() {
-    #![clippy::msrv = "1.57"]
     let local_i32 = 1;
     println!("don't expand='{}'", local_i32);
 }
 
+#[clippy::msrv = "1.58"]
 fn _meets_msrv() {
-    #![clippy::msrv = "1.58"]
     let local_i32 = 1;
     println!("expand='{}'", local_i32);
 }
index 2ce3b7fa960c6159e3c3a237d43220aa195f1516..a12abf8bef8af07bb4d53ab4f8227b26e6fd9a80 100644 (file)
@@ -1,5 +1,5 @@
 error: variables can be used directly in the `format!` string
-  --> $DIR/uninlined_format_args.rs:41:5
+  --> $DIR/uninlined_format_args.rs:40:5
    |
 LL |     println!("val='{}'", local_i32);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -12,7 +12,7 @@ LL +     println!("val='{local_i32}'");
    |
 
 error: variables can be used directly in the `format!` string
-  --> $DIR/uninlined_format_args.rs:42:5
+  --> $DIR/uninlined_format_args.rs:41:5
    |
 LL |     println!("val='{   }'", local_i32); // 3 spaces
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -24,7 +24,7 @@ LL +     println!("val='{local_i32}'"); // 3 spaces
    |
 
 error: variables can be used directly in the `format!` string
-  --> $DIR/uninlined_format_args.rs:43:5
+  --> $DIR/uninlined_format_args.rs:42:5
    |
 LL |     println!("val='{    }'", local_i32); // tab
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -36,7 +36,7 @@ LL +     println!("val='{local_i32}'"); // tab
    |
 
 error: variables can be used directly in the `format!` string
-  --> $DIR/uninlined_format_args.rs:44:5
+  --> $DIR/uninlined_format_args.rs:43:5
    |
 LL |     println!("val='{     }'", local_i32); // space+tab
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -48,7 +48,7 @@ LL +     println!("val='{local_i32}'"); // space+tab
    |
 
 error: variables can be used directly in the `format!` string
-  --> $DIR/uninlined_format_args.rs:45:5
+  --> $DIR/uninlined_format_args.rs:44:5
    |
 LL |     println!("val='{     }'", local_i32); // tab+space
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -60,7 +60,17 @@ LL +     println!("val='{local_i32}'"); // tab+space
    |
 
 error: variables can be used directly in the `format!` string
-  --> $DIR/uninlined_format_args.rs:51:5
+  --> $DIR/uninlined_format_args.rs:45:5
+   |
+LL | /     println!(
+LL | |         "val='{
+LL | |     }'",
+LL | |         local_i32
+LL | |     );
+   | |_____^
+
+error: variables can be used directly in the `format!` string
+  --> $DIR/uninlined_format_args.rs:50:5
    |
 LL |     println!("{}", local_i32);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -72,7 +82,7 @@ LL +     println!("{local_i32}");
    |
 
 error: variables can be used directly in the `format!` string
-  --> $DIR/uninlined_format_args.rs:52:5
+  --> $DIR/uninlined_format_args.rs:51:5
    |
 LL |     println!("{}", fn_arg);
    |     ^^^^^^^^^^^^^^^^^^^^^^
@@ -84,7 +94,7 @@ LL +     println!("{fn_arg}");
    |
 
 error: variables can be used directly in the `format!` string
-  --> $DIR/uninlined_format_args.rs:53:5
+  --> $DIR/uninlined_format_args.rs:52:5
    |
 LL |     println!("{:?}", local_i32);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -96,7 +106,7 @@ LL +     println!("{local_i32:?}");
    |
 
 error: variables can be used directly in the `format!` string
-  --> $DIR/uninlined_format_args.rs:54:5
+  --> $DIR/uninlined_format_args.rs:53:5
    |
 LL |     println!("{:#?}", local_i32);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -108,7 +118,7 @@ LL +     println!("{local_i32:#?}");
    |
 
 error: variables can be used directly in the `format!` string
-  --> $DIR/uninlined_format_args.rs:55:5
+  --> $DIR/uninlined_format_args.rs:54:5
    |
 LL |     println!("{:4}", local_i32);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -120,7 +130,7 @@ LL +     println!("{local_i32:4}");
    |
 
 error: variables can be used directly in the `format!` string
-  --> $DIR/uninlined_format_args.rs:56:5
+  --> $DIR/uninlined_format_args.rs:55:5
    |
 LL |     println!("{:04}", local_i32);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -132,7 +142,7 @@ LL +     println!("{local_i32:04}");
    |
 
 error: variables can be used directly in the `format!` string
-  --> $DIR/uninlined_format_args.rs:57:5
+  --> $DIR/uninlined_format_args.rs:56:5
    |
 LL |     println!("{:<3}", local_i32);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -144,7 +154,7 @@ LL +     println!("{local_i32:<3}");
    |
 
 error: variables can be used directly in the `format!` string
-  --> $DIR/uninlined_format_args.rs:58:5
+  --> $DIR/uninlined_format_args.rs:57:5
    |
 LL |     println!("{:#010x}", local_i32);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -156,7 +166,7 @@ LL +     println!("{local_i32:#010x}");
    |
 
 error: variables can be used directly in the `format!` string
-  --> $DIR/uninlined_format_args.rs:59:5
+  --> $DIR/uninlined_format_args.rs:58:5
    |
 LL |     println!("{:.1}", local_f64);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -167,45 +177,9 @@ LL -     println!("{:.1}", local_f64);
 LL +     println!("{local_f64:.1}");
    |
 
-error: variables can be used directly in the `format!` string
-  --> $DIR/uninlined_format_args.rs:60:5
-   |
-LL |     println!("Hello {} is {:.*}", "x", local_i32, local_f64);
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-help: change this to
-   |
-LL -     println!("Hello {} is {:.*}", "x", local_i32, local_f64);
-LL +     println!("Hello {} is {local_f64:.local_i32$}", "x");
-   |
-
-error: variables can be used directly in the `format!` string
-  --> $DIR/uninlined_format_args.rs:61:5
-   |
-LL |     println!("Hello {} is {:.*}", local_i32, 5, local_f64);
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-help: change this to
-   |
-LL -     println!("Hello {} is {:.*}", local_i32, 5, local_f64);
-LL +     println!("Hello {local_i32} is {local_f64:.*}", 5);
-   |
-
 error: variables can be used directly in the `format!` string
   --> $DIR/uninlined_format_args.rs:62:5
    |
-LL |     println!("Hello {} is {2:.*}", local_i32, 5, local_f64);
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-help: change this to
-   |
-LL -     println!("Hello {} is {2:.*}", local_i32, 5, local_f64);
-LL +     println!("Hello {local_i32} is {local_f64:.*}", 5);
-   |
-
-error: variables can be used directly in the `format!` string
-  --> $DIR/uninlined_format_args.rs:63:5
-   |
 LL |     println!("{} {}", local_i32, local_f64);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
@@ -218,18 +192,6 @@ LL +     println!("{local_i32} {local_f64}");
 error: variables can be used directly in the `format!` string
   --> $DIR/uninlined_format_args.rs:64:5
    |
-LL |     println!("{}, {}", local_i32, local_opt.unwrap());
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-help: change this to
-   |
-LL -     println!("{}, {}", local_i32, local_opt.unwrap());
-LL +     println!("{local_i32}, {}", local_opt.unwrap());
-   |
-
-error: variables can be used directly in the `format!` string
-  --> $DIR/uninlined_format_args.rs:65:5
-   |
 LL |     println!("{}", val);
    |     ^^^^^^^^^^^^^^^^^^^
    |
@@ -240,7 +202,7 @@ LL +     println!("{val}");
    |
 
 error: variables can be used directly in the `format!` string
-  --> $DIR/uninlined_format_args.rs:66:5
+  --> $DIR/uninlined_format_args.rs:65:5
    |
 LL |     println!("{}", v = val);
    |     ^^^^^^^^^^^^^^^^^^^^^^^
@@ -252,7 +214,7 @@ LL +     println!("{val}");
    |
 
 error: variables can be used directly in the `format!` string
-  --> $DIR/uninlined_format_args.rs:68:5
+  --> $DIR/uninlined_format_args.rs:67:5
    |
 LL |     println!("val='{/t }'", local_i32);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -264,7 +226,7 @@ LL +     println!("val='{local_i32}'");
    |
 
 error: variables can be used directly in the `format!` string
-  --> $DIR/uninlined_format_args.rs:69:5
+  --> $DIR/uninlined_format_args.rs:68:5
    |
 LL |     println!("val='{/n }'", local_i32);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -276,7 +238,7 @@ LL +     println!("val='{local_i32}'");
    |
 
 error: variables can be used directly in the `format!` string
-  --> $DIR/uninlined_format_args.rs:70:5
+  --> $DIR/uninlined_format_args.rs:69:5
    |
 LL |     println!("val='{local_i32}'", local_i32 = local_i32);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -288,7 +250,7 @@ LL +     println!("val='{local_i32}'");
    |
 
 error: variables can be used directly in the `format!` string
-  --> $DIR/uninlined_format_args.rs:71:5
+  --> $DIR/uninlined_format_args.rs:70:5
    |
 LL |     println!("val='{local_i32}'", local_i32 = fn_arg);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -300,7 +262,7 @@ LL +     println!("val='{fn_arg}'");
    |
 
 error: variables can be used directly in the `format!` string
-  --> $DIR/uninlined_format_args.rs:72:5
+  --> $DIR/uninlined_format_args.rs:71:5
    |
 LL |     println!("{0}", local_i32);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -312,7 +274,7 @@ LL +     println!("{local_i32}");
    |
 
 error: variables can be used directly in the `format!` string
-  --> $DIR/uninlined_format_args.rs:73:5
+  --> $DIR/uninlined_format_args.rs:72:5
    |
 LL |     println!("{0:?}", local_i32);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -324,7 +286,7 @@ LL +     println!("{local_i32:?}");
    |
 
 error: variables can be used directly in the `format!` string
-  --> $DIR/uninlined_format_args.rs:74:5
+  --> $DIR/uninlined_format_args.rs:73:5
    |
 LL |     println!("{0:#?}", local_i32);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -336,7 +298,7 @@ LL +     println!("{local_i32:#?}");
    |
 
 error: variables can be used directly in the `format!` string
-  --> $DIR/uninlined_format_args.rs:75:5
+  --> $DIR/uninlined_format_args.rs:74:5
    |
 LL |     println!("{0:04}", local_i32);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -348,7 +310,7 @@ LL +     println!("{local_i32:04}");
    |
 
 error: variables can be used directly in the `format!` string
-  --> $DIR/uninlined_format_args.rs:76:5
+  --> $DIR/uninlined_format_args.rs:75:5
    |
 LL |     println!("{0:<3}", local_i32);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -360,7 +322,7 @@ LL +     println!("{local_i32:<3}");
    |
 
 error: variables can be used directly in the `format!` string
-  --> $DIR/uninlined_format_args.rs:77:5
+  --> $DIR/uninlined_format_args.rs:76:5
    |
 LL |     println!("{0:#010x}", local_i32);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -372,7 +334,7 @@ LL +     println!("{local_i32:#010x}");
    |
 
 error: variables can be used directly in the `format!` string
-  --> $DIR/uninlined_format_args.rs:78:5
+  --> $DIR/uninlined_format_args.rs:77:5
    |
 LL |     println!("{0:.1}", local_f64);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -384,7 +346,7 @@ LL +     println!("{local_f64:.1}");
    |
 
 error: variables can be used directly in the `format!` string
-  --> $DIR/uninlined_format_args.rs:79:5
+  --> $DIR/uninlined_format_args.rs:78:5
    |
 LL |     println!("{0} {0}", local_i32);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -396,7 +358,7 @@ LL +     println!("{local_i32} {local_i32}");
    |
 
 error: variables can be used directly in the `format!` string
-  --> $DIR/uninlined_format_args.rs:80:5
+  --> $DIR/uninlined_format_args.rs:79:5
    |
 LL |     println!("{1} {} {0} {}", local_i32, local_f64);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -408,7 +370,7 @@ LL +     println!("{local_f64} {local_i32} {local_i32} {local_f64}");
    |
 
 error: variables can be used directly in the `format!` string
-  --> $DIR/uninlined_format_args.rs:81:5
+  --> $DIR/uninlined_format_args.rs:80:5
    |
 LL |     println!("{0} {1}", local_i32, local_f64);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -420,7 +382,7 @@ LL +     println!("{local_i32} {local_f64}");
    |
 
 error: variables can be used directly in the `format!` string
-  --> $DIR/uninlined_format_args.rs:82:5
+  --> $DIR/uninlined_format_args.rs:81:5
    |
 LL |     println!("{1} {0}", local_i32, local_f64);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -432,7 +394,7 @@ LL +     println!("{local_f64} {local_i32}");
    |
 
 error: variables can be used directly in the `format!` string
-  --> $DIR/uninlined_format_args.rs:83:5
+  --> $DIR/uninlined_format_args.rs:82:5
    |
 LL |     println!("{1} {0} {1} {0}", local_i32, local_f64);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -444,7 +406,7 @@ LL +     println!("{local_f64} {local_i32} {local_f64} {local_i32}");
    |
 
 error: variables can be used directly in the `format!` string
-  --> $DIR/uninlined_format_args.rs:85:5
+  --> $DIR/uninlined_format_args.rs:84:5
    |
 LL |     println!("{v}", v = local_i32);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -456,7 +418,7 @@ LL +     println!("{local_i32}");
    |
 
 error: variables can be used directly in the `format!` string
-  --> $DIR/uninlined_format_args.rs:86:5
+  --> $DIR/uninlined_format_args.rs:85:5
    |
 LL |     println!("{local_i32:0$}", width);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -468,7 +430,7 @@ LL +     println!("{local_i32:width$}");
    |
 
 error: variables can be used directly in the `format!` string
-  --> $DIR/uninlined_format_args.rs:87:5
+  --> $DIR/uninlined_format_args.rs:86:5
    |
 LL |     println!("{local_i32:w$}", w = width);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -480,7 +442,7 @@ LL +     println!("{local_i32:width$}");
    |
 
 error: variables can be used directly in the `format!` string
-  --> $DIR/uninlined_format_args.rs:88:5
+  --> $DIR/uninlined_format_args.rs:87:5
    |
 LL |     println!("{local_i32:.0$}", prec);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -492,7 +454,7 @@ LL +     println!("{local_i32:.prec$}");
    |
 
 error: variables can be used directly in the `format!` string
-  --> $DIR/uninlined_format_args.rs:89:5
+  --> $DIR/uninlined_format_args.rs:88:5
    |
 LL |     println!("{local_i32:.p$}", p = prec);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -504,7 +466,7 @@ LL +     println!("{local_i32:.prec$}");
    |
 
 error: variables can be used directly in the `format!` string
-  --> $DIR/uninlined_format_args.rs:90:5
+  --> $DIR/uninlined_format_args.rs:89:5
    |
 LL |     println!("{:0$}", v = val);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -516,7 +478,7 @@ LL +     println!("{val:val$}");
    |
 
 error: variables can be used directly in the `format!` string
-  --> $DIR/uninlined_format_args.rs:91:5
+  --> $DIR/uninlined_format_args.rs:90:5
    |
 LL |     println!("{0:0$}", v = val);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -528,7 +490,7 @@ LL +     println!("{val:val$}");
    |
 
 error: variables can be used directly in the `format!` string
-  --> $DIR/uninlined_format_args.rs:92:5
+  --> $DIR/uninlined_format_args.rs:91:5
    |
 LL |     println!("{:0$.0$}", v = val);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -540,7 +502,7 @@ LL +     println!("{val:val$.val$}");
    |
 
 error: variables can be used directly in the `format!` string
-  --> $DIR/uninlined_format_args.rs:93:5
+  --> $DIR/uninlined_format_args.rs:92:5
    |
 LL |     println!("{0:0$.0$}", v = val);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -552,7 +514,7 @@ LL +     println!("{val:val$.val$}");
    |
 
 error: variables can be used directly in the `format!` string
-  --> $DIR/uninlined_format_args.rs:94:5
+  --> $DIR/uninlined_format_args.rs:93:5
    |
 LL |     println!("{0:0$.v$}", v = val);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -564,7 +526,7 @@ LL +     println!("{val:val$.val$}");
    |
 
 error: variables can be used directly in the `format!` string
-  --> $DIR/uninlined_format_args.rs:95:5
+  --> $DIR/uninlined_format_args.rs:94:5
    |
 LL |     println!("{0:v$.0$}", v = val);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -576,7 +538,7 @@ LL +     println!("{val:val$.val$}");
    |
 
 error: variables can be used directly in the `format!` string
-  --> $DIR/uninlined_format_args.rs:96:5
+  --> $DIR/uninlined_format_args.rs:95:5
    |
 LL |     println!("{v:0$.0$}", v = val);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -588,7 +550,7 @@ LL +     println!("{val:val$.val$}");
    |
 
 error: variables can be used directly in the `format!` string
-  --> $DIR/uninlined_format_args.rs:97:5
+  --> $DIR/uninlined_format_args.rs:96:5
    |
 LL |     println!("{v:v$.0$}", v = val);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -600,7 +562,7 @@ LL +     println!("{val:val$.val$}");
    |
 
 error: variables can be used directly in the `format!` string
-  --> $DIR/uninlined_format_args.rs:98:5
+  --> $DIR/uninlined_format_args.rs:97:5
    |
 LL |     println!("{v:0$.v$}", v = val);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -612,7 +574,7 @@ LL +     println!("{val:val$.val$}");
    |
 
 error: variables can be used directly in the `format!` string
-  --> $DIR/uninlined_format_args.rs:99:5
+  --> $DIR/uninlined_format_args.rs:98:5
    |
 LL |     println!("{v:v$.v$}", v = val);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -624,7 +586,7 @@ LL +     println!("{val:val$.val$}");
    |
 
 error: variables can be used directly in the `format!` string
-  --> $DIR/uninlined_format_args.rs:100:5
+  --> $DIR/uninlined_format_args.rs:99:5
    |
 LL |     println!("{:0$}", width);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^
@@ -636,7 +598,7 @@ LL +     println!("{width:width$}");
    |
 
 error: variables can be used directly in the `format!` string
-  --> $DIR/uninlined_format_args.rs:101:5
+  --> $DIR/uninlined_format_args.rs:100:5
    |
 LL |     println!("{:1$}", local_i32, width);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -648,7 +610,7 @@ LL +     println!("{local_i32:width$}");
    |
 
 error: variables can be used directly in the `format!` string
-  --> $DIR/uninlined_format_args.rs:102:5
+  --> $DIR/uninlined_format_args.rs:101:5
    |
 LL |     println!("{:w$}", w = width);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -660,7 +622,7 @@ LL +     println!("{width:width$}");
    |
 
 error: variables can be used directly in the `format!` string
-  --> $DIR/uninlined_format_args.rs:103:5
+  --> $DIR/uninlined_format_args.rs:102:5
    |
 LL |     println!("{:w$}", local_i32, w = width);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -672,7 +634,7 @@ LL +     println!("{local_i32:width$}");
    |
 
 error: variables can be used directly in the `format!` string
-  --> $DIR/uninlined_format_args.rs:104:5
+  --> $DIR/uninlined_format_args.rs:103:5
    |
 LL |     println!("{:.0$}", prec);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^
@@ -684,7 +646,7 @@ LL +     println!("{prec:.prec$}");
    |
 
 error: variables can be used directly in the `format!` string
-  --> $DIR/uninlined_format_args.rs:105:5
+  --> $DIR/uninlined_format_args.rs:104:5
    |
 LL |     println!("{:.1$}", local_i32, prec);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -696,7 +658,7 @@ LL +     println!("{local_i32:.prec$}");
    |
 
 error: variables can be used directly in the `format!` string
-  --> $DIR/uninlined_format_args.rs:106:5
+  --> $DIR/uninlined_format_args.rs:105:5
    |
 LL |     println!("{:.p$}", p = prec);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -708,7 +670,7 @@ LL +     println!("{prec:.prec$}");
    |
 
 error: variables can be used directly in the `format!` string
-  --> $DIR/uninlined_format_args.rs:107:5
+  --> $DIR/uninlined_format_args.rs:106:5
    |
 LL |     println!("{:.p$}", local_i32, p = prec);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -720,7 +682,7 @@ LL +     println!("{local_i32:.prec$}");
    |
 
 error: variables can be used directly in the `format!` string
-  --> $DIR/uninlined_format_args.rs:108:5
+  --> $DIR/uninlined_format_args.rs:107:5
    |
 LL |     println!("{:0$.1$}", width, prec);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -732,7 +694,7 @@ LL +     println!("{width:width$.prec$}");
    |
 
 error: variables can be used directly in the `format!` string
-  --> $DIR/uninlined_format_args.rs:109:5
+  --> $DIR/uninlined_format_args.rs:108:5
    |
 LL |     println!("{:0$.w$}", width, w = prec);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -744,7 +706,7 @@ LL +     println!("{width:width$.prec$}");
    |
 
 error: variables can be used directly in the `format!` string
-  --> $DIR/uninlined_format_args.rs:110:5
+  --> $DIR/uninlined_format_args.rs:109:5
    |
 LL |     println!("{:1$.2$}", local_f64, width, prec);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -756,7 +718,7 @@ LL +     println!("{local_f64:width$.prec$}");
    |
 
 error: variables can be used directly in the `format!` string
-  --> $DIR/uninlined_format_args.rs:111:5
+  --> $DIR/uninlined_format_args.rs:110:5
    |
 LL |     println!("{:1$.2$} {0} {1} {2}", local_f64, width, prec);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -768,7 +730,16 @@ LL +     println!("{local_f64:width$.prec$} {local_f64} {width} {prec}");
    |
 
 error: variables can be used directly in the `format!` string
-  --> $DIR/uninlined_format_args.rs:123:5
+  --> $DIR/uninlined_format_args.rs:111:5
+   |
+LL | /     println!(
+LL | |         "{0:1$.2$} {0:2$.1$} {1:0$.2$} {1:2$.0$} {2:0$.1$} {2:1$.0$}",
+LL | |         local_i32, width, prec,
+LL | |     );
+   | |_____^
+
+error: variables can be used directly in the `format!` string
+  --> $DIR/uninlined_format_args.rs:122:5
    |
 LL |     println!("Width = {}, value with width = {:0$}", local_i32, local_f64);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -780,7 +751,7 @@ LL +     println!("Width = {local_i32}, value with width = {local_f64:local_i32$
    |
 
 error: variables can be used directly in the `format!` string
-  --> $DIR/uninlined_format_args.rs:124:5
+  --> $DIR/uninlined_format_args.rs:123:5
    |
 LL |     println!("{:w$.p$}", local_i32, w = width, p = prec);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -792,7 +763,7 @@ LL +     println!("{local_i32:width$.prec$}");
    |
 
 error: variables can be used directly in the `format!` string
-  --> $DIR/uninlined_format_args.rs:125:5
+  --> $DIR/uninlined_format_args.rs:124:5
    |
 LL |     println!("{:w$.p$}", w = width, p = prec);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -804,7 +775,7 @@ LL +     println!("{width:width$.prec$}");
    |
 
 error: variables can be used directly in the `format!` string
-  --> $DIR/uninlined_format_args.rs:126:20
+  --> $DIR/uninlined_format_args.rs:125:20
    |
 LL |     println!("{}", format!("{}", local_i32));
    |                    ^^^^^^^^^^^^^^^^^^^^^^^^
@@ -816,7 +787,17 @@ LL +     println!("{}", format!("{local_i32}"));
    |
 
 error: variables can be used directly in the `format!` string
-  --> $DIR/uninlined_format_args.rs:149:5
+  --> $DIR/uninlined_format_args.rs:143:5
+   |
+LL | /     println!(
+LL | |         "{}",
+LL | |         // comment with a comma , in it
+LL | |         val,
+LL | |     );
+   | |_____^
+
+error: variables can be used directly in the `format!` string
+  --> $DIR/uninlined_format_args.rs:148:5
    |
 LL |     println!("{}", /* comment with a comma , in it */ val);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -828,7 +809,7 @@ LL +     println!("{val}");
    |
 
 error: variables can be used directly in the `format!` string
-  --> $DIR/uninlined_format_args.rs:155:9
+  --> $DIR/uninlined_format_args.rs:154:9
    |
 LL |         panic!("p1 {}", local_i32);
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -840,7 +821,7 @@ LL +         panic!("p1 {local_i32}");
    |
 
 error: variables can be used directly in the `format!` string
-  --> $DIR/uninlined_format_args.rs:158:9
+  --> $DIR/uninlined_format_args.rs:157:9
    |
 LL |         panic!("p2 {0}", local_i32);
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -852,7 +833,7 @@ LL +         panic!("p2 {local_i32}");
    |
 
 error: variables can be used directly in the `format!` string
-  --> $DIR/uninlined_format_args.rs:161:9
+  --> $DIR/uninlined_format_args.rs:160:9
    |
 LL |         panic!("p3 {local_i32}", local_i32 = local_i32);
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -864,7 +845,7 @@ LL +         panic!("p3 {local_i32}");
    |
 
 error: variables can be used directly in the `format!` string
-  --> $DIR/uninlined_format_args.rs:181:5
+  --> $DIR/uninlined_format_args.rs:180:5
    |
 LL |     println!("expand='{}'", local_i32);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -875,5 +856,5 @@ LL -     println!("expand='{}'", local_i32);
 LL +     println!("expand='{local_i32}'");
    |
 
-error: aborting due to 73 previous errors
+error: aborting due to 72 previous errors
 
index ec8c6abfab91e725891f268967c59dabcb101e13..2f7e2997e739d50ec990455b60cbf898820ad2bf 100644 (file)
@@ -41,6 +41,17 @@ fn main() {
     // do not lint cast to alias type
     1 as I32Alias;
     &1 as &I32Alias;
+
+    // issue #9960
+    macro_rules! bind_var {
+        ($id:ident, $e:expr) => {{
+            let $id = 0usize;
+            let _ = $e != 0usize;
+            let $id = 0isize;
+            let _ = $e != 0usize;
+        }}
+    }
+    bind_var!(x, (x as usize) + 1);
 }
 
 type I32Alias = i32;
@@ -85,6 +96,9 @@ mod fixable {
 
         let _ = 1 as I32Alias;
         let _ = &1 as &I32Alias;
+
+        let x = 1i32;
+        let _ = &{ x };
     }
 
     type I32Alias = i32;
index 5213cdc269bd4c5a9aec63cb2c5ff31a87e4ccf9..54dd46ba59f104a1172d14c9363b09b08ad79627 100644 (file)
@@ -41,6 +41,17 @@ pub fn $a() -> $b {
     // do not lint cast to alias type
     1 as I32Alias;
     &1 as &I32Alias;
+
+    // issue #9960
+    macro_rules! bind_var {
+        ($id:ident, $e:expr) => {{
+            let $id = 0usize;
+            let _ = $e != 0usize;
+            let $id = 0isize;
+            let _ = $e != 0usize;
+        }}
+    }
+    bind_var!(x, (x as usize) + 1);
 }
 
 type I32Alias = i32;
@@ -85,6 +96,9 @@ fn main() {
 
         let _ = 1 as I32Alias;
         let _ = &1 as &I32Alias;
+
+        let x = 1i32;
+        let _ = &(x as i32);
     }
 
     type I32Alias = i32;
index e5c3dd5e53f876e2489d702319694058069fd6d4..fcee4ee2a65cc9fa267c65354382292421c3ede8 100644 (file)
@@ -49,136 +49,142 @@ LL |     1_f32 as f32;
    |     ^^^^^^^^^^^^ help: try: `1_f32`
 
 error: casting integer literal to `f32` is unnecessary
-  --> $DIR/unnecessary_cast.rs:53:9
+  --> $DIR/unnecessary_cast.rs:64:9
    |
 LL |         100 as f32;
    |         ^^^^^^^^^^ help: try: `100_f32`
 
 error: casting integer literal to `f64` is unnecessary
-  --> $DIR/unnecessary_cast.rs:54:9
+  --> $DIR/unnecessary_cast.rs:65:9
    |
 LL |         100 as f64;
    |         ^^^^^^^^^^ help: try: `100_f64`
 
 error: casting integer literal to `f64` is unnecessary
-  --> $DIR/unnecessary_cast.rs:55:9
+  --> $DIR/unnecessary_cast.rs:66:9
    |
 LL |         100_i32 as f64;
    |         ^^^^^^^^^^^^^^ help: try: `100_f64`
 
 error: casting integer literal to `f32` is unnecessary
-  --> $DIR/unnecessary_cast.rs:56:17
+  --> $DIR/unnecessary_cast.rs:67:17
    |
 LL |         let _ = -100 as f32;
    |                 ^^^^^^^^^^^ help: try: `-100_f32`
 
 error: casting integer literal to `f64` is unnecessary
-  --> $DIR/unnecessary_cast.rs:57:17
+  --> $DIR/unnecessary_cast.rs:68:17
    |
 LL |         let _ = -100 as f64;
    |                 ^^^^^^^^^^^ help: try: `-100_f64`
 
 error: casting integer literal to `f64` is unnecessary
-  --> $DIR/unnecessary_cast.rs:58:17
+  --> $DIR/unnecessary_cast.rs:69:17
    |
 LL |         let _ = -100_i32 as f64;
    |                 ^^^^^^^^^^^^^^^ help: try: `-100_f64`
 
 error: casting float literal to `f32` is unnecessary
-  --> $DIR/unnecessary_cast.rs:59:9
+  --> $DIR/unnecessary_cast.rs:70:9
    |
 LL |         100. as f32;
    |         ^^^^^^^^^^^ help: try: `100_f32`
 
 error: casting float literal to `f64` is unnecessary
-  --> $DIR/unnecessary_cast.rs:60:9
+  --> $DIR/unnecessary_cast.rs:71:9
    |
 LL |         100. as f64;
    |         ^^^^^^^^^^^ help: try: `100_f64`
 
 error: casting integer literal to `u32` is unnecessary
-  --> $DIR/unnecessary_cast.rs:72:9
+  --> $DIR/unnecessary_cast.rs:83:9
    |
 LL |         1 as u32;
    |         ^^^^^^^^ help: try: `1_u32`
 
 error: casting integer literal to `i32` is unnecessary
-  --> $DIR/unnecessary_cast.rs:73:9
+  --> $DIR/unnecessary_cast.rs:84:9
    |
 LL |         0x10 as i32;
    |         ^^^^^^^^^^^ help: try: `0x10_i32`
 
 error: casting integer literal to `usize` is unnecessary
-  --> $DIR/unnecessary_cast.rs:74:9
+  --> $DIR/unnecessary_cast.rs:85:9
    |
 LL |         0b10 as usize;
    |         ^^^^^^^^^^^^^ help: try: `0b10_usize`
 
 error: casting integer literal to `u16` is unnecessary
-  --> $DIR/unnecessary_cast.rs:75:9
+  --> $DIR/unnecessary_cast.rs:86:9
    |
 LL |         0o73 as u16;
    |         ^^^^^^^^^^^ help: try: `0o73_u16`
 
 error: casting integer literal to `u32` is unnecessary
-  --> $DIR/unnecessary_cast.rs:76:9
+  --> $DIR/unnecessary_cast.rs:87:9
    |
 LL |         1_000_000_000 as u32;
    |         ^^^^^^^^^^^^^^^^^^^^ help: try: `1_000_000_000_u32`
 
 error: casting float literal to `f64` is unnecessary
-  --> $DIR/unnecessary_cast.rs:78:9
+  --> $DIR/unnecessary_cast.rs:89:9
    |
 LL |         1.0 as f64;
    |         ^^^^^^^^^^ help: try: `1.0_f64`
 
 error: casting float literal to `f32` is unnecessary
-  --> $DIR/unnecessary_cast.rs:79:9
+  --> $DIR/unnecessary_cast.rs:90:9
    |
 LL |         0.5 as f32;
    |         ^^^^^^^^^^ help: try: `0.5_f32`
 
 error: casting integer literal to `i32` is unnecessary
-  --> $DIR/unnecessary_cast.rs:83:17
+  --> $DIR/unnecessary_cast.rs:94:17
    |
 LL |         let _ = -1 as i32;
    |                 ^^^^^^^^^ help: try: `-1_i32`
 
 error: casting float literal to `f32` is unnecessary
-  --> $DIR/unnecessary_cast.rs:84:17
+  --> $DIR/unnecessary_cast.rs:95:17
    |
 LL |         let _ = -1.0 as f32;
    |                 ^^^^^^^^^^^ help: try: `-1.0_f32`
 
+error: casting to the same type is unnecessary (`i32` -> `i32`)
+  --> $DIR/unnecessary_cast.rs:101:18
+   |
+LL |         let _ = &(x as i32);
+   |                  ^^^^^^^^^^ help: try: `{ x }`
+
 error: casting integer literal to `i32` is unnecessary
-  --> $DIR/unnecessary_cast.rs:93:22
+  --> $DIR/unnecessary_cast.rs:107: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
+  --> $DIR/unnecessary_cast.rs:109:22
    |
 LL |         let _: i64 = -(1) as i64;
    |                      ^^^^^^^^^^^ help: try: `-1_i64`
 
 error: casting float literal to `f64` is unnecessary
-  --> $DIR/unnecessary_cast.rs:102:22
+  --> $DIR/unnecessary_cast.rs:116:22
    |
 LL |         let _: f64 = (-8.0 as f64).exp();
    |                      ^^^^^^^^^^^^^ help: try: `(-8.0_f64)`
 
 error: casting float literal to `f64` is unnecessary
-  --> $DIR/unnecessary_cast.rs:104:23
+  --> $DIR/unnecessary_cast.rs:118:23
    |
 LL |         let _: f64 = -(8.0 as f64).exp(); // should suggest `-8.0_f64.exp()` here not to change code behavior
    |                       ^^^^^^^^^^^^ help: try: `8.0_f64`
 
 error: casting to the same type is unnecessary (`f32` -> `f32`)
-  --> $DIR/unnecessary_cast.rs:112:20
+  --> $DIR/unnecessary_cast.rs:126:20
    |
 LL |         let _num = foo() as f32;
    |                    ^^^^^^^^^^^^ help: try: `foo()`
 
-error: aborting due to 30 previous errors
+error: aborting due to 31 previous errors
 
index ce4a82e021745d45e532710d2c93cd82be091988..22e9bd8bdc510f69b48e09fa5b9c45685437eecb 100644 (file)
@@ -33,6 +33,14 @@ impl Drop for Issue9427 {
     }
 }
 
+struct Issue9427FollowUp;
+
+impl Drop for Issue9427FollowUp {
+    fn drop(&mut self) {
+        panic!("side effect drop");
+    }
+}
+
 fn main() {
     let astronomers_pi = 10;
     let ext_arr: [usize; 1] = [2];
@@ -87,6 +95,7 @@ fn main() {
 
     // Should not lint - bool
     let _ = (0 == 1).then(|| Issue9427(0)); // Issue9427 has a significant drop
+    let _ = false.then(|| Issue9427FollowUp); // Issue9427FollowUp has a significant drop
 
     // should not lint, bind_instead_of_map takes priority
     let _ = Some(10).and_then(|idx| Some(ext_arr[idx]));
@@ -133,13 +142,13 @@ fn main() {
     let _: Result<usize, usize> = res.or(Ok(astronomers_pi));
     let _: Result<usize, usize> = res.or(Ok(ext_str.some_field));
     let _: Result<usize, usize> = res.
-        // some lines
-        // some lines
-        // some lines
-        // some lines
-        // some lines
-        // some lines
-        or(Ok(ext_str.some_field));
+    // some lines
+    // some lines
+    // some lines
+    // some lines
+    // some lines
+    // some lines
+    or(Ok(ext_str.some_field));
 
     // neither bind_instead_of_map nor unnecessary_lazy_eval applies here
     let _: Result<usize, usize> = res.and_then(|x| Err(x));
index 59cdf66285463e3e69dcb750cdcb194ce0ca7066..8726d84a23fcfd8d438134400a1e357d8c0503df 100644 (file)
@@ -33,6 +33,14 @@ fn drop(&mut self) {
     }
 }
 
+struct Issue9427FollowUp;
+
+impl Drop for Issue9427FollowUp {
+    fn drop(&mut self) {
+        panic!("side effect drop");
+    }
+}
+
 fn main() {
     let astronomers_pi = 10;
     let ext_arr: [usize; 1] = [2];
@@ -87,6 +95,7 @@ fn main() {
 
     // Should not lint - bool
     let _ = (0 == 1).then(|| Issue9427(0)); // Issue9427 has a significant drop
+    let _ = false.then(|| Issue9427FollowUp); // Issue9427FollowUp has a significant drop
 
     // should not lint, bind_instead_of_map takes priority
     let _ = Some(10).and_then(|idx| Some(ext_arr[idx]));
@@ -133,13 +142,13 @@ fn main() {
     let _: Result<usize, usize> = res.or_else(|_| Ok(astronomers_pi));
     let _: Result<usize, usize> = res.or_else(|_| Ok(ext_str.some_field));
     let _: Result<usize, usize> = res.
-        // some lines
-        // some lines
-        // some lines
-        // some lines
-        // some lines
-        // some lines
-        or_else(|_| Ok(ext_str.some_field));
+    // some lines
+    // some lines
+    // some lines
+    // some lines
+    // some lines
+    // some lines
+    or_else(|_| Ok(ext_str.some_field));
 
     // neither bind_instead_of_map nor unnecessary_lazy_eval applies here
     let _: Result<usize, usize> = res.and_then(|x| Err(x));
index 8a9ece4aa7e54548a4e841688cff2b2864713de6..0339755442c5a7dfd1bdb5d4ac13822f0bcd2f80 100644 (file)
@@ -1,5 +1,5 @@
 error: unnecessary closure used to substitute value for `Option::None`
-  --> $DIR/unnecessary_lazy_eval.rs:48:13
+  --> $DIR/unnecessary_lazy_eval.rs:56:13
    |
 LL |     let _ = opt.unwrap_or_else(|| 2);
    |             ^^^^--------------------
@@ -9,7 +9,7 @@ LL |     let _ = opt.unwrap_or_else(|| 2);
    = note: `-D clippy::unnecessary-lazy-evaluations` implied by `-D warnings`
 
 error: unnecessary closure used to substitute value for `Option::None`
-  --> $DIR/unnecessary_lazy_eval.rs:49:13
+  --> $DIR/unnecessary_lazy_eval.rs:57:13
    |
 LL |     let _ = opt.unwrap_or_else(|| astronomers_pi);
    |             ^^^^---------------------------------
@@ -17,7 +17,7 @@ LL |     let _ = opt.unwrap_or_else(|| astronomers_pi);
    |                 help: use `unwrap_or(..)` instead: `unwrap_or(astronomers_pi)`
 
 error: unnecessary closure used to substitute value for `Option::None`
-  --> $DIR/unnecessary_lazy_eval.rs:50:13
+  --> $DIR/unnecessary_lazy_eval.rs:58:13
    |
 LL |     let _ = opt.unwrap_or_else(|| ext_str.some_field);
    |             ^^^^-------------------------------------
@@ -25,7 +25,7 @@ LL |     let _ = opt.unwrap_or_else(|| ext_str.some_field);
    |                 help: use `unwrap_or(..)` instead: `unwrap_or(ext_str.some_field)`
 
 error: unnecessary closure used to substitute value for `Option::None`
-  --> $DIR/unnecessary_lazy_eval.rs:52:13
+  --> $DIR/unnecessary_lazy_eval.rs:60:13
    |
 LL |     let _ = opt.and_then(|_| ext_opt);
    |             ^^^^---------------------
@@ -33,7 +33,7 @@ LL |     let _ = opt.and_then(|_| ext_opt);
    |                 help: use `and(..)` instead: `and(ext_opt)`
 
 error: unnecessary closure used to substitute value for `Option::None`
-  --> $DIR/unnecessary_lazy_eval.rs:53:13
+  --> $DIR/unnecessary_lazy_eval.rs:61:13
    |
 LL |     let _ = opt.or_else(|| ext_opt);
    |             ^^^^-------------------
@@ -41,7 +41,7 @@ LL |     let _ = opt.or_else(|| ext_opt);
    |                 help: use `or(..)` instead: `or(ext_opt)`
 
 error: unnecessary closure used to substitute value for `Option::None`
-  --> $DIR/unnecessary_lazy_eval.rs:54:13
+  --> $DIR/unnecessary_lazy_eval.rs:62:13
    |
 LL |     let _ = opt.or_else(|| None);
    |             ^^^^----------------
@@ -49,7 +49,7 @@ LL |     let _ = opt.or_else(|| None);
    |                 help: use `or(..)` instead: `or(None)`
 
 error: unnecessary closure used to substitute value for `Option::None`
-  --> $DIR/unnecessary_lazy_eval.rs:55:13
+  --> $DIR/unnecessary_lazy_eval.rs:63:13
    |
 LL |     let _ = opt.get_or_insert_with(|| 2);
    |             ^^^^------------------------
@@ -57,7 +57,7 @@ LL |     let _ = opt.get_or_insert_with(|| 2);
    |                 help: use `get_or_insert(..)` instead: `get_or_insert(2)`
 
 error: unnecessary closure used to substitute value for `Option::None`
-  --> $DIR/unnecessary_lazy_eval.rs:56:13
+  --> $DIR/unnecessary_lazy_eval.rs:64:13
    |
 LL |     let _ = opt.ok_or_else(|| 2);
    |             ^^^^----------------
@@ -65,7 +65,7 @@ LL |     let _ = opt.ok_or_else(|| 2);
    |                 help: use `ok_or(..)` instead: `ok_or(2)`
 
 error: unnecessary closure used to substitute value for `Option::None`
-  --> $DIR/unnecessary_lazy_eval.rs:57:13
+  --> $DIR/unnecessary_lazy_eval.rs:65:13
    |
 LL |     let _ = nested_tuple_opt.unwrap_or_else(|| Some((1, 2)));
    |             ^^^^^^^^^^^^^^^^^-------------------------------
@@ -73,7 +73,7 @@ LL |     let _ = nested_tuple_opt.unwrap_or_else(|| Some((1, 2)));
    |                              help: use `unwrap_or(..)` instead: `unwrap_or(Some((1, 2)))`
 
 error: unnecessary closure used with `bool::then`
-  --> $DIR/unnecessary_lazy_eval.rs:58:13
+  --> $DIR/unnecessary_lazy_eval.rs:66:13
    |
 LL |     let _ = cond.then(|| astronomers_pi);
    |             ^^^^^-----------------------
@@ -81,7 +81,7 @@ LL |     let _ = cond.then(|| astronomers_pi);
    |                  help: use `then_some(..)` instead: `then_some(astronomers_pi)`
 
 error: unnecessary closure used to substitute value for `Option::None`
-  --> $DIR/unnecessary_lazy_eval.rs:61:13
+  --> $DIR/unnecessary_lazy_eval.rs:69:13
    |
 LL |     let _ = Some(10).unwrap_or_else(|| 2);
    |             ^^^^^^^^^--------------------
@@ -89,7 +89,7 @@ LL |     let _ = Some(10).unwrap_or_else(|| 2);
    |                      help: use `unwrap_or(..)` instead: `unwrap_or(2)`
 
 error: unnecessary closure used to substitute value for `Option::None`
-  --> $DIR/unnecessary_lazy_eval.rs:62:13
+  --> $DIR/unnecessary_lazy_eval.rs:70:13
    |
 LL |     let _ = Some(10).and_then(|_| ext_opt);
    |             ^^^^^^^^^---------------------
@@ -97,7 +97,7 @@ LL |     let _ = Some(10).and_then(|_| ext_opt);
    |                      help: use `and(..)` instead: `and(ext_opt)`
 
 error: unnecessary closure used to substitute value for `Option::None`
-  --> $DIR/unnecessary_lazy_eval.rs:63:28
+  --> $DIR/unnecessary_lazy_eval.rs:71:28
    |
 LL |     let _: Option<usize> = None.or_else(|| ext_opt);
    |                            ^^^^^-------------------
@@ -105,7 +105,7 @@ LL |     let _: Option<usize> = None.or_else(|| ext_opt);
    |                                 help: use `or(..)` instead: `or(ext_opt)`
 
 error: unnecessary closure used to substitute value for `Option::None`
-  --> $DIR/unnecessary_lazy_eval.rs:64:13
+  --> $DIR/unnecessary_lazy_eval.rs:72:13
    |
 LL |     let _ = None.get_or_insert_with(|| 2);
    |             ^^^^^------------------------
@@ -113,7 +113,7 @@ LL |     let _ = None.get_or_insert_with(|| 2);
    |                  help: use `get_or_insert(..)` instead: `get_or_insert(2)`
 
 error: unnecessary closure used to substitute value for `Option::None`
-  --> $DIR/unnecessary_lazy_eval.rs:65:35
+  --> $DIR/unnecessary_lazy_eval.rs:73:35
    |
 LL |     let _: Result<usize, usize> = None.ok_or_else(|| 2);
    |                                   ^^^^^----------------
@@ -121,7 +121,7 @@ LL |     let _: Result<usize, usize> = None.ok_or_else(|| 2);
    |                                        help: use `ok_or(..)` instead: `ok_or(2)`
 
 error: unnecessary closure used to substitute value for `Option::None`
-  --> $DIR/unnecessary_lazy_eval.rs:66:28
+  --> $DIR/unnecessary_lazy_eval.rs:74:28
    |
 LL |     let _: Option<usize> = None.or_else(|| None);
    |                            ^^^^^----------------
@@ -129,7 +129,7 @@ LL |     let _: Option<usize> = None.or_else(|| None);
    |                                 help: use `or(..)` instead: `or(None)`
 
 error: unnecessary closure used to substitute value for `Option::None`
-  --> $DIR/unnecessary_lazy_eval.rs:69:13
+  --> $DIR/unnecessary_lazy_eval.rs:77:13
    |
 LL |     let _ = deep.0.unwrap_or_else(|| 2);
    |             ^^^^^^^--------------------
@@ -137,7 +137,7 @@ LL |     let _ = deep.0.unwrap_or_else(|| 2);
    |                    help: use `unwrap_or(..)` instead: `unwrap_or(2)`
 
 error: unnecessary closure used to substitute value for `Option::None`
-  --> $DIR/unnecessary_lazy_eval.rs:70:13
+  --> $DIR/unnecessary_lazy_eval.rs:78:13
    |
 LL |     let _ = deep.0.and_then(|_| ext_opt);
    |             ^^^^^^^---------------------
@@ -145,7 +145,7 @@ LL |     let _ = deep.0.and_then(|_| ext_opt);
    |                    help: use `and(..)` instead: `and(ext_opt)`
 
 error: unnecessary closure used to substitute value for `Option::None`
-  --> $DIR/unnecessary_lazy_eval.rs:71:13
+  --> $DIR/unnecessary_lazy_eval.rs:79:13
    |
 LL |     let _ = deep.0.or_else(|| None);
    |             ^^^^^^^----------------
@@ -153,7 +153,7 @@ LL |     let _ = deep.0.or_else(|| None);
    |                    help: use `or(..)` instead: `or(None)`
 
 error: unnecessary closure used to substitute value for `Option::None`
-  --> $DIR/unnecessary_lazy_eval.rs:72:13
+  --> $DIR/unnecessary_lazy_eval.rs:80:13
    |
 LL |     let _ = deep.0.get_or_insert_with(|| 2);
    |             ^^^^^^^------------------------
@@ -161,7 +161,7 @@ LL |     let _ = deep.0.get_or_insert_with(|| 2);
    |                    help: use `get_or_insert(..)` instead: `get_or_insert(2)`
 
 error: unnecessary closure used to substitute value for `Option::None`
-  --> $DIR/unnecessary_lazy_eval.rs:73:13
+  --> $DIR/unnecessary_lazy_eval.rs:81:13
    |
 LL |     let _ = deep.0.ok_or_else(|| 2);
    |             ^^^^^^^----------------
@@ -169,7 +169,7 @@ LL |     let _ = deep.0.ok_or_else(|| 2);
    |                    help: use `ok_or(..)` instead: `ok_or(2)`
 
 error: unnecessary closure used to substitute value for `Option::None`
-  --> $DIR/unnecessary_lazy_eval.rs:96:28
+  --> $DIR/unnecessary_lazy_eval.rs:105:28
    |
 LL |     let _: Option<usize> = None.or_else(|| Some(3));
    |                            ^^^^^-------------------
@@ -177,7 +177,7 @@ LL |     let _: Option<usize> = None.or_else(|| Some(3));
    |                                 help: use `or(..)` instead: `or(Some(3))`
 
 error: unnecessary closure used to substitute value for `Option::None`
-  --> $DIR/unnecessary_lazy_eval.rs:97:13
+  --> $DIR/unnecessary_lazy_eval.rs:106:13
    |
 LL |     let _ = deep.0.or_else(|| Some(3));
    |             ^^^^^^^-------------------
@@ -185,7 +185,7 @@ LL |     let _ = deep.0.or_else(|| Some(3));
    |                    help: use `or(..)` instead: `or(Some(3))`
 
 error: unnecessary closure used to substitute value for `Option::None`
-  --> $DIR/unnecessary_lazy_eval.rs:98:13
+  --> $DIR/unnecessary_lazy_eval.rs:107:13
    |
 LL |     let _ = opt.or_else(|| Some(3));
    |             ^^^^-------------------
@@ -193,7 +193,7 @@ LL |     let _ = opt.or_else(|| Some(3));
    |                 help: use `or(..)` instead: `or(Some(3))`
 
 error: unnecessary closure used to substitute value for `Result::Err`
-  --> $DIR/unnecessary_lazy_eval.rs:104:13
+  --> $DIR/unnecessary_lazy_eval.rs:113:13
    |
 LL |     let _ = res2.unwrap_or_else(|_| 2);
    |             ^^^^^---------------------
@@ -201,7 +201,7 @@ LL |     let _ = res2.unwrap_or_else(|_| 2);
    |                  help: use `unwrap_or(..)` instead: `unwrap_or(2)`
 
 error: unnecessary closure used to substitute value for `Result::Err`
-  --> $DIR/unnecessary_lazy_eval.rs:105:13
+  --> $DIR/unnecessary_lazy_eval.rs:114:13
    |
 LL |     let _ = res2.unwrap_or_else(|_| astronomers_pi);
    |             ^^^^^----------------------------------
@@ -209,7 +209,7 @@ LL |     let _ = res2.unwrap_or_else(|_| astronomers_pi);
    |                  help: use `unwrap_or(..)` instead: `unwrap_or(astronomers_pi)`
 
 error: unnecessary closure used to substitute value for `Result::Err`
-  --> $DIR/unnecessary_lazy_eval.rs:106:13
+  --> $DIR/unnecessary_lazy_eval.rs:115:13
    |
 LL |     let _ = res2.unwrap_or_else(|_| ext_str.some_field);
    |             ^^^^^--------------------------------------
@@ -217,7 +217,7 @@ LL |     let _ = res2.unwrap_or_else(|_| ext_str.some_field);
    |                  help: use `unwrap_or(..)` instead: `unwrap_or(ext_str.some_field)`
 
 error: unnecessary closure used to substitute value for `Result::Err`
-  --> $DIR/unnecessary_lazy_eval.rs:128:35
+  --> $DIR/unnecessary_lazy_eval.rs:137:35
    |
 LL |     let _: Result<usize, usize> = res.and_then(|_| Err(2));
    |                                   ^^^^--------------------
@@ -225,7 +225,7 @@ LL |     let _: Result<usize, usize> = res.and_then(|_| Err(2));
    |                                       help: use `and(..)` instead: `and(Err(2))`
 
 error: unnecessary closure used to substitute value for `Result::Err`
-  --> $DIR/unnecessary_lazy_eval.rs:129:35
+  --> $DIR/unnecessary_lazy_eval.rs:138:35
    |
 LL |     let _: Result<usize, usize> = res.and_then(|_| Err(astronomers_pi));
    |                                   ^^^^---------------------------------
@@ -233,7 +233,7 @@ LL |     let _: Result<usize, usize> = res.and_then(|_| Err(astronomers_pi));
    |                                       help: use `and(..)` instead: `and(Err(astronomers_pi))`
 
 error: unnecessary closure used to substitute value for `Result::Err`
-  --> $DIR/unnecessary_lazy_eval.rs:130:35
+  --> $DIR/unnecessary_lazy_eval.rs:139:35
    |
 LL |     let _: Result<usize, usize> = res.and_then(|_| Err(ext_str.some_field));
    |                                   ^^^^-------------------------------------
@@ -241,7 +241,7 @@ LL |     let _: Result<usize, usize> = res.and_then(|_| Err(ext_str.some_field))
    |                                       help: use `and(..)` instead: `and(Err(ext_str.some_field))`
 
 error: unnecessary closure used to substitute value for `Result::Err`
-  --> $DIR/unnecessary_lazy_eval.rs:132:35
+  --> $DIR/unnecessary_lazy_eval.rs:141:35
    |
 LL |     let _: Result<usize, usize> = res.or_else(|_| Ok(2));
    |                                   ^^^^------------------
@@ -249,7 +249,7 @@ LL |     let _: Result<usize, usize> = res.or_else(|_| Ok(2));
    |                                       help: use `or(..)` instead: `or(Ok(2))`
 
 error: unnecessary closure used to substitute value for `Result::Err`
-  --> $DIR/unnecessary_lazy_eval.rs:133:35
+  --> $DIR/unnecessary_lazy_eval.rs:142:35
    |
 LL |     let _: Result<usize, usize> = res.or_else(|_| Ok(astronomers_pi));
    |                                   ^^^^-------------------------------
@@ -257,7 +257,7 @@ LL |     let _: Result<usize, usize> = res.or_else(|_| Ok(astronomers_pi));
    |                                       help: use `or(..)` instead: `or(Ok(astronomers_pi))`
 
 error: unnecessary closure used to substitute value for `Result::Err`
-  --> $DIR/unnecessary_lazy_eval.rs:134:35
+  --> $DIR/unnecessary_lazy_eval.rs:143:35
    |
 LL |     let _: Result<usize, usize> = res.or_else(|_| Ok(ext_str.some_field));
    |                                   ^^^^-----------------------------------
@@ -265,19 +265,19 @@ LL |     let _: Result<usize, usize> = res.or_else(|_| Ok(ext_str.some_field));
    |                                       help: use `or(..)` instead: `or(Ok(ext_str.some_field))`
 
 error: unnecessary closure used to substitute value for `Result::Err`
-  --> $DIR/unnecessary_lazy_eval.rs:135:35
+  --> $DIR/unnecessary_lazy_eval.rs:144:35
    |
 LL |       let _: Result<usize, usize> = res.
    |  ___________________________________^
-LL | |         // some lines
-LL | |         // some lines
-LL | |         // some lines
+LL | |     // some lines
+LL | |     // some lines
+LL | |     // some lines
 ...  |
-LL | |         // some lines
-LL | |         or_else(|_| Ok(ext_str.some_field));
-   | |_________----------------------------------^
-   |           |
-   |           help: use `or(..)` instead: `or(Ok(ext_str.some_field))`
+LL | |     // some lines
+LL | |     or_else(|_| Ok(ext_str.some_field));
+   | |_____----------------------------------^
+   |       |
+   |       help: use `or(..)` instead: `or(Ok(ext_str.some_field))`
 
 error: aborting due to 34 previous errors
 
index bf0ec8deb3458bccdc65a4151a8237241f6a0626..d37163570abe07ee61fba6db3942e538e6382601 100644 (file)
@@ -76,4 +76,13 @@ fn main() {
     DropStruct { ..get_drop_struct() };
     DropEnum::Tuple(get_number());
     DropEnum::Struct { field: get_number() };
+
+    // Issue #9954
+    fn one() -> i8 {
+        1
+    }
+    macro_rules! use_expr {
+        ($($e:expr),*) => {{ $($e;)* }}
+    }
+    use_expr!(isize::MIN / -(one() as isize), i8::MIN / -one());
 }
index 08cb9ab522ee0d7f22ea647908102b06b73b36a7..a14fd4bca0efde72bd30a1acec726665cdb6f9d8 100644 (file)
@@ -80,4 +80,13 @@ fn main() {
     DropStruct { ..get_drop_struct() };
     DropEnum::Tuple(get_number());
     DropEnum::Struct { field: get_number() };
+
+    // Issue #9954
+    fn one() -> i8 {
+        1
+    }
+    macro_rules! use_expr {
+        ($($e:expr),*) => {{ $($e;)* }}
+    }
+    use_expr!(isize::MIN / -(one() as isize), i8::MIN / -one());
 }
diff --git a/src/tools/clippy/tests/ui/unnecessary_safety_comment.rs b/src/tools/clippy/tests/ui/unnecessary_safety_comment.rs
new file mode 100644 (file)
index 0000000..7fefea7
--- /dev/null
@@ -0,0 +1,51 @@
+#![warn(clippy::undocumented_unsafe_blocks, clippy::unnecessary_safety_comment)]
+#![allow(clippy::let_unit_value, clippy::missing_safety_doc)]
+
+mod unsafe_items_invalid_comment {
+    // SAFETY:
+    const CONST: u32 = 0;
+    // SAFETY:
+    static STATIC: u32 = 0;
+    // SAFETY:
+    struct Struct;
+    // SAFETY:
+    enum Enum {}
+    // SAFETY:
+    mod module {}
+}
+
+mod unnecessary_from_macro {
+    trait T {}
+
+    macro_rules! no_safety_comment {
+        ($t:ty) => {
+            impl T for $t {}
+        };
+    }
+
+    // FIXME: This is not caught
+    // Safety: unnecessary
+    no_safety_comment!(());
+
+    macro_rules! with_safety_comment {
+        ($t:ty) => {
+            // Safety: unnecessary
+            impl T for $t {}
+        };
+    }
+
+    with_safety_comment!(i32);
+}
+
+fn unnecessary_on_stmt_and_expr() -> u32 {
+    // SAFETY: unnecessary
+    let num = 42;
+
+    // SAFETY: unnecessary
+    if num > 24 {}
+
+    // SAFETY: unnecessary
+    24
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/unnecessary_safety_comment.stderr b/src/tools/clippy/tests/ui/unnecessary_safety_comment.stderr
new file mode 100644 (file)
index 0000000..7b2af67
--- /dev/null
@@ -0,0 +1,115 @@
+error: constant item has unnecessary safety comment
+  --> $DIR/unnecessary_safety_comment.rs:6:5
+   |
+LL |     const CONST: u32 = 0;
+   |     ^^^^^^^^^^^^^^^^^^^^^
+   |
+help: consider removing the safety comment
+  --> $DIR/unnecessary_safety_comment.rs:5:5
+   |
+LL |     // SAFETY:
+   |     ^^^^^^^^^^
+   = note: `-D clippy::unnecessary-safety-comment` implied by `-D warnings`
+
+error: static item has unnecessary safety comment
+  --> $DIR/unnecessary_safety_comment.rs:8:5
+   |
+LL |     static STATIC: u32 = 0;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: consider removing the safety comment
+  --> $DIR/unnecessary_safety_comment.rs:7:5
+   |
+LL |     // SAFETY:
+   |     ^^^^^^^^^^
+
+error: struct has unnecessary safety comment
+  --> $DIR/unnecessary_safety_comment.rs:10:5
+   |
+LL |     struct Struct;
+   |     ^^^^^^^^^^^^^^
+   |
+help: consider removing the safety comment
+  --> $DIR/unnecessary_safety_comment.rs:9:5
+   |
+LL |     // SAFETY:
+   |     ^^^^^^^^^^
+
+error: enum has unnecessary safety comment
+  --> $DIR/unnecessary_safety_comment.rs:12:5
+   |
+LL |     enum Enum {}
+   |     ^^^^^^^^^^^^
+   |
+help: consider removing the safety comment
+  --> $DIR/unnecessary_safety_comment.rs:11:5
+   |
+LL |     // SAFETY:
+   |     ^^^^^^^^^^
+
+error: module has unnecessary safety comment
+  --> $DIR/unnecessary_safety_comment.rs:14:5
+   |
+LL |     mod module {}
+   |     ^^^^^^^^^^^^^
+   |
+help: consider removing the safety comment
+  --> $DIR/unnecessary_safety_comment.rs:13:5
+   |
+LL |     // SAFETY:
+   |     ^^^^^^^^^^
+
+error: impl has unnecessary safety comment
+  --> $DIR/unnecessary_safety_comment.rs:33:13
+   |
+LL |             impl T for $t {}
+   |             ^^^^^^^^^^^^^^^^
+...
+LL |     with_safety_comment!(i32);
+   |     ------------------------- in this macro invocation
+   |
+help: consider removing the safety comment
+  --> $DIR/unnecessary_safety_comment.rs:32:13
+   |
+LL |             // Safety: unnecessary
+   |             ^^^^^^^^^^^^^^^^^^^^^^
+   = note: this error originates in the macro `with_safety_comment` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: expression has unnecessary safety comment
+  --> $DIR/unnecessary_safety_comment.rs:48:5
+   |
+LL |     24
+   |     ^^
+   |
+help: consider removing the safety comment
+  --> $DIR/unnecessary_safety_comment.rs:47:5
+   |
+LL |     // SAFETY: unnecessary
+   |     ^^^^^^^^^^^^^^^^^^^^^^
+
+error: statement has unnecessary safety comment
+  --> $DIR/unnecessary_safety_comment.rs:42:5
+   |
+LL |     let num = 42;
+   |     ^^^^^^^^^^^^^
+   |
+help: consider removing the safety comment
+  --> $DIR/unnecessary_safety_comment.rs:41:5
+   |
+LL |     // SAFETY: unnecessary
+   |     ^^^^^^^^^^^^^^^^^^^^^^
+
+error: statement has unnecessary safety comment
+  --> $DIR/unnecessary_safety_comment.rs:45:5
+   |
+LL |     if num > 24 {}
+   |     ^^^^^^^^^^^^^^
+   |
+help: consider removing the safety comment
+  --> $DIR/unnecessary_safety_comment.rs:44:5
+   |
+LL |     // SAFETY: unnecessary
+   |     ^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 9 previous errors
+
index fe09aad06bc84d792c10d99a04e8fdd37f05bdbd..ddeda795f81793e8d70d7109a16c958a4821f7f0 100644 (file)
@@ -2,7 +2,6 @@
 
 #![allow(clippy::needless_borrow, clippy::ptr_arg)]
 #![warn(clippy::unnecessary_to_owned)]
-#![feature(custom_inner_attributes)]
 
 use std::borrow::Cow;
 use std::ffi::{CStr, CString, OsStr, OsString};
@@ -215,14 +214,14 @@ fn get_file_path(_file_type: &FileType) -> Result<std::path::PathBuf, std::io::E
 
 fn require_string(_: &String) {}
 
+#[clippy::msrv = "1.35"]
 fn _msrv_1_35() {
-    #![clippy::msrv = "1.35"]
     // `copied` was stabilized in 1.36, so clippy should use `cloned`.
     let _ = &["x"][..].iter().cloned();
 }
 
+#[clippy::msrv = "1.36"]
 fn _msrv_1_36() {
-    #![clippy::msrv = "1.36"]
     let _ = &["x"][..].iter().copied();
 }
 
@@ -426,3 +425,32 @@ mod issue_9504 {
         foo(std::path::PathBuf::new().to_string_lossy().to_string()).await;
     }
 }
+
+mod issue_9771a {
+    #![allow(dead_code)]
+
+    use std::marker::PhantomData;
+
+    pub struct Key<K: AsRef<[u8]>, V: ?Sized>(K, PhantomData<V>);
+
+    impl<K: AsRef<[u8]>, V: ?Sized> Key<K, V> {
+        pub fn new(key: K) -> Key<K, V> {
+            Key(key, PhantomData)
+        }
+    }
+
+    pub fn pkh(pkh: &[u8]) -> Key<Vec<u8>, String> {
+        Key::new([b"pkh-", pkh].concat().to_vec())
+    }
+}
+
+mod issue_9771b {
+    #![allow(dead_code)]
+
+    pub struct Key<K: AsRef<[u8]>>(K);
+
+    pub fn from(c: &[u8]) -> Key<Vec<u8>> {
+        let v = [c].concat();
+        Key(v.to_vec())
+    }
+}
index 3de6d0903c0f1d0e083fa5de7fc89cfc331fe1a1..95d2576733cd75ea8e42bf0ea127fb8983f7e451 100644 (file)
@@ -2,7 +2,6 @@
 
 #![allow(clippy::needless_borrow, clippy::ptr_arg)]
 #![warn(clippy::unnecessary_to_owned)]
-#![feature(custom_inner_attributes)]
 
 use std::borrow::Cow;
 use std::ffi::{CStr, CString, OsStr, OsString};
@@ -215,14 +214,14 @@ fn get_file_path(_file_type: &FileType) -> Result<std::path::PathBuf, std::io::E
 
 fn require_string(_: &String) {}
 
+#[clippy::msrv = "1.35"]
 fn _msrv_1_35() {
-    #![clippy::msrv = "1.35"]
     // `copied` was stabilized in 1.36, so clippy should use `cloned`.
     let _ = &["x"][..].to_vec().into_iter();
 }
 
+#[clippy::msrv = "1.36"]
 fn _msrv_1_36() {
-    #![clippy::msrv = "1.36"]
     let _ = &["x"][..].to_vec().into_iter();
 }
 
@@ -426,3 +425,32 @@ async fn bar() {
         foo(std::path::PathBuf::new().to_string_lossy().to_string()).await;
     }
 }
+
+mod issue_9771a {
+    #![allow(dead_code)]
+
+    use std::marker::PhantomData;
+
+    pub struct Key<K: AsRef<[u8]>, V: ?Sized>(K, PhantomData<V>);
+
+    impl<K: AsRef<[u8]>, V: ?Sized> Key<K, V> {
+        pub fn new(key: K) -> Key<K, V> {
+            Key(key, PhantomData)
+        }
+    }
+
+    pub fn pkh(pkh: &[u8]) -> Key<Vec<u8>, String> {
+        Key::new([b"pkh-", pkh].concat().to_vec())
+    }
+}
+
+mod issue_9771b {
+    #![allow(dead_code)]
+
+    pub struct Key<K: AsRef<[u8]>>(K);
+
+    pub fn from(c: &[u8]) -> Key<Vec<u8>> {
+        let v = [c].concat();
+        Key(v.to_vec())
+    }
+}
index 02bf45a33fbe1913ed1adaaee6fe7bddb4f7259b..4918fe35598602f8c3b19eb45c1b6f16c2053d48 100644 (file)
@@ -1,66 +1,66 @@
 error: redundant clone
-  --> $DIR/unnecessary_to_owned.rs:151:64
+  --> $DIR/unnecessary_to_owned.rs:150:64
    |
 LL |     require_c_str(&CString::from_vec_with_nul(vec![0]).unwrap().to_owned());
    |                                                                ^^^^^^^^^^^ help: remove this
    |
 note: this value is dropped without further use
-  --> $DIR/unnecessary_to_owned.rs:151:20
+  --> $DIR/unnecessary_to_owned.rs:150:20
    |
 LL |     require_c_str(&CString::from_vec_with_nul(vec![0]).unwrap().to_owned());
    |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    = note: `-D clippy::redundant-clone` implied by `-D warnings`
 
 error: redundant clone
-  --> $DIR/unnecessary_to_owned.rs:152:40
+  --> $DIR/unnecessary_to_owned.rs:151:40
    |
 LL |     require_os_str(&OsString::from("x").to_os_string());
    |                                        ^^^^^^^^^^^^^^^ help: remove this
    |
 note: this value is dropped without further use
-  --> $DIR/unnecessary_to_owned.rs:152:21
+  --> $DIR/unnecessary_to_owned.rs:151:21
    |
 LL |     require_os_str(&OsString::from("x").to_os_string());
    |                     ^^^^^^^^^^^^^^^^^^^
 
 error: redundant clone
-  --> $DIR/unnecessary_to_owned.rs:153:48
+  --> $DIR/unnecessary_to_owned.rs:152:48
    |
 LL |     require_path(&std::path::PathBuf::from("x").to_path_buf());
    |                                                ^^^^^^^^^^^^^^ help: remove this
    |
 note: this value is dropped without further use
-  --> $DIR/unnecessary_to_owned.rs:153:19
+  --> $DIR/unnecessary_to_owned.rs:152:19
    |
 LL |     require_path(&std::path::PathBuf::from("x").to_path_buf());
    |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: redundant clone
-  --> $DIR/unnecessary_to_owned.rs:154:35
+  --> $DIR/unnecessary_to_owned.rs:153:35
    |
 LL |     require_str(&String::from("x").to_string());
    |                                   ^^^^^^^^^^^^ help: remove this
    |
 note: this value is dropped without further use
-  --> $DIR/unnecessary_to_owned.rs:154:18
+  --> $DIR/unnecessary_to_owned.rs:153:18
    |
 LL |     require_str(&String::from("x").to_string());
    |                  ^^^^^^^^^^^^^^^^^
 
 error: redundant clone
-  --> $DIR/unnecessary_to_owned.rs:155:39
+  --> $DIR/unnecessary_to_owned.rs:154:39
    |
 LL |     require_slice(&[String::from("x")].to_owned());
    |                                       ^^^^^^^^^^^ help: remove this
    |
 note: this value is dropped without further use
-  --> $DIR/unnecessary_to_owned.rs:155:20
+  --> $DIR/unnecessary_to_owned.rs:154:20
    |
 LL |     require_slice(&[String::from("x")].to_owned());
    |                    ^^^^^^^^^^^^^^^^^^^
 
 error: unnecessary use of `into_owned`
-  --> $DIR/unnecessary_to_owned.rs:60:36
+  --> $DIR/unnecessary_to_owned.rs:59:36
    |
 LL |     require_c_str(&Cow::from(c_str).into_owned());
    |                                    ^^^^^^^^^^^^^ help: remove this
@@ -68,415 +68,415 @@ LL |     require_c_str(&Cow::from(c_str).into_owned());
    = note: `-D clippy::unnecessary-to-owned` implied by `-D warnings`
 
 error: unnecessary use of `to_owned`
-  --> $DIR/unnecessary_to_owned.rs:61:19
+  --> $DIR/unnecessary_to_owned.rs:60:19
    |
 LL |     require_c_str(&c_str.to_owned());
    |                   ^^^^^^^^^^^^^^^^^ help: use: `c_str`
 
 error: unnecessary use of `to_os_string`
-  --> $DIR/unnecessary_to_owned.rs:63:20
+  --> $DIR/unnecessary_to_owned.rs:62:20
    |
 LL |     require_os_str(&os_str.to_os_string());
    |                    ^^^^^^^^^^^^^^^^^^^^^^ help: use: `os_str`
 
 error: unnecessary use of `into_owned`
-  --> $DIR/unnecessary_to_owned.rs:64:38
+  --> $DIR/unnecessary_to_owned.rs:63:38
    |
 LL |     require_os_str(&Cow::from(os_str).into_owned());
    |                                      ^^^^^^^^^^^^^ help: remove this
 
 error: unnecessary use of `to_owned`
-  --> $DIR/unnecessary_to_owned.rs:65:20
+  --> $DIR/unnecessary_to_owned.rs:64:20
    |
 LL |     require_os_str(&os_str.to_owned());
    |                    ^^^^^^^^^^^^^^^^^^ help: use: `os_str`
 
 error: unnecessary use of `to_path_buf`
-  --> $DIR/unnecessary_to_owned.rs:67:18
+  --> $DIR/unnecessary_to_owned.rs:66:18
    |
 LL |     require_path(&path.to_path_buf());
    |                  ^^^^^^^^^^^^^^^^^^^ help: use: `path`
 
 error: unnecessary use of `into_owned`
-  --> $DIR/unnecessary_to_owned.rs:68:34
+  --> $DIR/unnecessary_to_owned.rs:67:34
    |
 LL |     require_path(&Cow::from(path).into_owned());
    |                                  ^^^^^^^^^^^^^ help: remove this
 
 error: unnecessary use of `to_owned`
-  --> $DIR/unnecessary_to_owned.rs:69:18
+  --> $DIR/unnecessary_to_owned.rs:68:18
    |
 LL |     require_path(&path.to_owned());
    |                  ^^^^^^^^^^^^^^^^ help: use: `path`
 
 error: unnecessary use of `to_string`
-  --> $DIR/unnecessary_to_owned.rs:71:17
+  --> $DIR/unnecessary_to_owned.rs:70:17
    |
 LL |     require_str(&s.to_string());
    |                 ^^^^^^^^^^^^^^ help: use: `s`
 
 error: unnecessary use of `into_owned`
-  --> $DIR/unnecessary_to_owned.rs:72:30
+  --> $DIR/unnecessary_to_owned.rs:71:30
    |
 LL |     require_str(&Cow::from(s).into_owned());
    |                              ^^^^^^^^^^^^^ help: remove this
 
 error: unnecessary use of `to_owned`
-  --> $DIR/unnecessary_to_owned.rs:73:17
+  --> $DIR/unnecessary_to_owned.rs:72:17
    |
 LL |     require_str(&s.to_owned());
    |                 ^^^^^^^^^^^^^ help: use: `s`
 
 error: unnecessary use of `to_string`
-  --> $DIR/unnecessary_to_owned.rs:74:17
+  --> $DIR/unnecessary_to_owned.rs:73:17
    |
 LL |     require_str(&x_ref.to_string());
    |                 ^^^^^^^^^^^^^^^^^^ help: use: `x_ref.as_ref()`
 
 error: unnecessary use of `to_vec`
-  --> $DIR/unnecessary_to_owned.rs:76:19
+  --> $DIR/unnecessary_to_owned.rs:75:19
    |
 LL |     require_slice(&slice.to_vec());
    |                   ^^^^^^^^^^^^^^^ help: use: `slice`
 
 error: unnecessary use of `into_owned`
-  --> $DIR/unnecessary_to_owned.rs:77:36
+  --> $DIR/unnecessary_to_owned.rs:76:36
    |
 LL |     require_slice(&Cow::from(slice).into_owned());
    |                                    ^^^^^^^^^^^^^ help: remove this
 
 error: unnecessary use of `to_owned`
-  --> $DIR/unnecessary_to_owned.rs:78:19
+  --> $DIR/unnecessary_to_owned.rs:77:19
    |
 LL |     require_slice(&array.to_owned());
    |                   ^^^^^^^^^^^^^^^^^ help: use: `array.as_ref()`
 
 error: unnecessary use of `to_owned`
-  --> $DIR/unnecessary_to_owned.rs:79:19
+  --> $DIR/unnecessary_to_owned.rs:78:19
    |
 LL |     require_slice(&array_ref.to_owned());
    |                   ^^^^^^^^^^^^^^^^^^^^^ help: use: `array_ref.as_ref()`
 
 error: unnecessary use of `to_owned`
-  --> $DIR/unnecessary_to_owned.rs:80:19
+  --> $DIR/unnecessary_to_owned.rs:79:19
    |
 LL |     require_slice(&slice.to_owned());
    |                   ^^^^^^^^^^^^^^^^^ help: use: `slice`
 
 error: unnecessary use of `into_owned`
-  --> $DIR/unnecessary_to_owned.rs:83:42
+  --> $DIR/unnecessary_to_owned.rs:82:42
    |
 LL |     require_x(&Cow::<X>::Owned(x.clone()).into_owned());
    |                                          ^^^^^^^^^^^^^ help: remove this
 
 error: unnecessary use of `to_owned`
-  --> $DIR/unnecessary_to_owned.rs:86:25
+  --> $DIR/unnecessary_to_owned.rs:85:25
    |
 LL |     require_deref_c_str(c_str.to_owned());
    |                         ^^^^^^^^^^^^^^^^ help: use: `c_str`
 
 error: unnecessary use of `to_owned`
-  --> $DIR/unnecessary_to_owned.rs:87:26
+  --> $DIR/unnecessary_to_owned.rs:86:26
    |
 LL |     require_deref_os_str(os_str.to_owned());
    |                          ^^^^^^^^^^^^^^^^^ help: use: `os_str`
 
 error: unnecessary use of `to_owned`
-  --> $DIR/unnecessary_to_owned.rs:88:24
+  --> $DIR/unnecessary_to_owned.rs:87:24
    |
 LL |     require_deref_path(path.to_owned());
    |                        ^^^^^^^^^^^^^^^ help: use: `path`
 
 error: unnecessary use of `to_owned`
-  --> $DIR/unnecessary_to_owned.rs:89:23
+  --> $DIR/unnecessary_to_owned.rs:88:23
    |
 LL |     require_deref_str(s.to_owned());
    |                       ^^^^^^^^^^^^ help: use: `s`
 
 error: unnecessary use of `to_owned`
-  --> $DIR/unnecessary_to_owned.rs:90:25
+  --> $DIR/unnecessary_to_owned.rs:89:25
    |
 LL |     require_deref_slice(slice.to_owned());
    |                         ^^^^^^^^^^^^^^^^ help: use: `slice`
 
 error: unnecessary use of `to_owned`
-  --> $DIR/unnecessary_to_owned.rs:92:30
+  --> $DIR/unnecessary_to_owned.rs:91:30
    |
 LL |     require_impl_deref_c_str(c_str.to_owned());
    |                              ^^^^^^^^^^^^^^^^ help: use: `c_str`
 
 error: unnecessary use of `to_owned`
-  --> $DIR/unnecessary_to_owned.rs:93:31
+  --> $DIR/unnecessary_to_owned.rs:92:31
    |
 LL |     require_impl_deref_os_str(os_str.to_owned());
    |                               ^^^^^^^^^^^^^^^^^ help: use: `os_str`
 
 error: unnecessary use of `to_owned`
-  --> $DIR/unnecessary_to_owned.rs:94:29
+  --> $DIR/unnecessary_to_owned.rs:93:29
    |
 LL |     require_impl_deref_path(path.to_owned());
    |                             ^^^^^^^^^^^^^^^ help: use: `path`
 
 error: unnecessary use of `to_owned`
-  --> $DIR/unnecessary_to_owned.rs:95:28
+  --> $DIR/unnecessary_to_owned.rs:94:28
    |
 LL |     require_impl_deref_str(s.to_owned());
    |                            ^^^^^^^^^^^^ help: use: `s`
 
 error: unnecessary use of `to_owned`
-  --> $DIR/unnecessary_to_owned.rs:96:30
+  --> $DIR/unnecessary_to_owned.rs:95:30
    |
 LL |     require_impl_deref_slice(slice.to_owned());
    |                              ^^^^^^^^^^^^^^^^ help: use: `slice`
 
 error: unnecessary use of `to_owned`
-  --> $DIR/unnecessary_to_owned.rs:98:29
+  --> $DIR/unnecessary_to_owned.rs:97:29
    |
 LL |     require_deref_str_slice(s.to_owned(), slice.to_owned());
    |                             ^^^^^^^^^^^^ help: use: `s`
 
 error: unnecessary use of `to_owned`
-  --> $DIR/unnecessary_to_owned.rs:98:43
+  --> $DIR/unnecessary_to_owned.rs:97:43
    |
 LL |     require_deref_str_slice(s.to_owned(), slice.to_owned());
    |                                           ^^^^^^^^^^^^^^^^ help: use: `slice`
 
 error: unnecessary use of `to_owned`
-  --> $DIR/unnecessary_to_owned.rs:99:29
+  --> $DIR/unnecessary_to_owned.rs:98:29
    |
 LL |     require_deref_slice_str(slice.to_owned(), s.to_owned());
    |                             ^^^^^^^^^^^^^^^^ help: use: `slice`
 
 error: unnecessary use of `to_owned`
-  --> $DIR/unnecessary_to_owned.rs:99:47
+  --> $DIR/unnecessary_to_owned.rs:98:47
    |
 LL |     require_deref_slice_str(slice.to_owned(), s.to_owned());
    |                                               ^^^^^^^^^^^^ help: use: `s`
 
 error: unnecessary use of `to_owned`
-  --> $DIR/unnecessary_to_owned.rs:101:26
+  --> $DIR/unnecessary_to_owned.rs:100:26
    |
 LL |     require_as_ref_c_str(c_str.to_owned());
    |                          ^^^^^^^^^^^^^^^^ help: use: `c_str`
 
 error: unnecessary use of `to_owned`
-  --> $DIR/unnecessary_to_owned.rs:102:27
+  --> $DIR/unnecessary_to_owned.rs:101:27
    |
 LL |     require_as_ref_os_str(os_str.to_owned());
    |                           ^^^^^^^^^^^^^^^^^ help: use: `os_str`
 
 error: unnecessary use of `to_owned`
-  --> $DIR/unnecessary_to_owned.rs:103:25
+  --> $DIR/unnecessary_to_owned.rs:102:25
    |
 LL |     require_as_ref_path(path.to_owned());
    |                         ^^^^^^^^^^^^^^^ help: use: `path`
 
 error: unnecessary use of `to_owned`
-  --> $DIR/unnecessary_to_owned.rs:104:24
+  --> $DIR/unnecessary_to_owned.rs:103:24
    |
 LL |     require_as_ref_str(s.to_owned());
    |                        ^^^^^^^^^^^^ help: use: `s`
 
 error: unnecessary use of `to_owned`
-  --> $DIR/unnecessary_to_owned.rs:105:24
+  --> $DIR/unnecessary_to_owned.rs:104:24
    |
 LL |     require_as_ref_str(x.to_owned());
    |                        ^^^^^^^^^^^^ help: use: `&x`
 
 error: unnecessary use of `to_owned`
-  --> $DIR/unnecessary_to_owned.rs:106:26
+  --> $DIR/unnecessary_to_owned.rs:105:26
    |
 LL |     require_as_ref_slice(array.to_owned());
    |                          ^^^^^^^^^^^^^^^^ help: use: `array`
 
 error: unnecessary use of `to_owned`
-  --> $DIR/unnecessary_to_owned.rs:107:26
+  --> $DIR/unnecessary_to_owned.rs:106:26
    |
 LL |     require_as_ref_slice(array_ref.to_owned());
    |                          ^^^^^^^^^^^^^^^^^^^^ help: use: `array_ref`
 
 error: unnecessary use of `to_owned`
-  --> $DIR/unnecessary_to_owned.rs:108:26
+  --> $DIR/unnecessary_to_owned.rs:107:26
    |
 LL |     require_as_ref_slice(slice.to_owned());
    |                          ^^^^^^^^^^^^^^^^ help: use: `slice`
 
 error: unnecessary use of `to_owned`
-  --> $DIR/unnecessary_to_owned.rs:110:31
+  --> $DIR/unnecessary_to_owned.rs:109:31
    |
 LL |     require_impl_as_ref_c_str(c_str.to_owned());
    |                               ^^^^^^^^^^^^^^^^ help: use: `c_str`
 
 error: unnecessary use of `to_owned`
-  --> $DIR/unnecessary_to_owned.rs:111:32
+  --> $DIR/unnecessary_to_owned.rs:110:32
    |
 LL |     require_impl_as_ref_os_str(os_str.to_owned());
    |                                ^^^^^^^^^^^^^^^^^ help: use: `os_str`
 
 error: unnecessary use of `to_owned`
-  --> $DIR/unnecessary_to_owned.rs:112:30
+  --> $DIR/unnecessary_to_owned.rs:111:30
    |
 LL |     require_impl_as_ref_path(path.to_owned());
    |                              ^^^^^^^^^^^^^^^ help: use: `path`
 
 error: unnecessary use of `to_owned`
-  --> $DIR/unnecessary_to_owned.rs:113:29
+  --> $DIR/unnecessary_to_owned.rs:112:29
    |
 LL |     require_impl_as_ref_str(s.to_owned());
    |                             ^^^^^^^^^^^^ help: use: `s`
 
 error: unnecessary use of `to_owned`
-  --> $DIR/unnecessary_to_owned.rs:114:29
+  --> $DIR/unnecessary_to_owned.rs:113:29
    |
 LL |     require_impl_as_ref_str(x.to_owned());
    |                             ^^^^^^^^^^^^ help: use: `&x`
 
 error: unnecessary use of `to_owned`
-  --> $DIR/unnecessary_to_owned.rs:115:31
+  --> $DIR/unnecessary_to_owned.rs:114:31
    |
 LL |     require_impl_as_ref_slice(array.to_owned());
    |                               ^^^^^^^^^^^^^^^^ help: use: `array`
 
 error: unnecessary use of `to_owned`
-  --> $DIR/unnecessary_to_owned.rs:116:31
+  --> $DIR/unnecessary_to_owned.rs:115:31
    |
 LL |     require_impl_as_ref_slice(array_ref.to_owned());
    |                               ^^^^^^^^^^^^^^^^^^^^ help: use: `array_ref`
 
 error: unnecessary use of `to_owned`
-  --> $DIR/unnecessary_to_owned.rs:117:31
+  --> $DIR/unnecessary_to_owned.rs:116:31
    |
 LL |     require_impl_as_ref_slice(slice.to_owned());
    |                               ^^^^^^^^^^^^^^^^ help: use: `slice`
 
 error: unnecessary use of `to_owned`
-  --> $DIR/unnecessary_to_owned.rs:119:30
+  --> $DIR/unnecessary_to_owned.rs:118:30
    |
 LL |     require_as_ref_str_slice(s.to_owned(), array.to_owned());
    |                              ^^^^^^^^^^^^ help: use: `s`
 
 error: unnecessary use of `to_owned`
-  --> $DIR/unnecessary_to_owned.rs:119:44
+  --> $DIR/unnecessary_to_owned.rs:118:44
    |
 LL |     require_as_ref_str_slice(s.to_owned(), array.to_owned());
    |                                            ^^^^^^^^^^^^^^^^ help: use: `array`
 
 error: unnecessary use of `to_owned`
-  --> $DIR/unnecessary_to_owned.rs:120:30
+  --> $DIR/unnecessary_to_owned.rs:119:30
    |
 LL |     require_as_ref_str_slice(s.to_owned(), array_ref.to_owned());
    |                              ^^^^^^^^^^^^ help: use: `s`
 
 error: unnecessary use of `to_owned`
-  --> $DIR/unnecessary_to_owned.rs:120:44
+  --> $DIR/unnecessary_to_owned.rs:119:44
    |
 LL |     require_as_ref_str_slice(s.to_owned(), array_ref.to_owned());
    |                                            ^^^^^^^^^^^^^^^^^^^^ help: use: `array_ref`
 
 error: unnecessary use of `to_owned`
-  --> $DIR/unnecessary_to_owned.rs:121:30
+  --> $DIR/unnecessary_to_owned.rs:120:30
    |
 LL |     require_as_ref_str_slice(s.to_owned(), slice.to_owned());
    |                              ^^^^^^^^^^^^ help: use: `s`
 
 error: unnecessary use of `to_owned`
-  --> $DIR/unnecessary_to_owned.rs:121:44
+  --> $DIR/unnecessary_to_owned.rs:120:44
    |
 LL |     require_as_ref_str_slice(s.to_owned(), slice.to_owned());
    |                                            ^^^^^^^^^^^^^^^^ help: use: `slice`
 
 error: unnecessary use of `to_owned`
-  --> $DIR/unnecessary_to_owned.rs:122:30
+  --> $DIR/unnecessary_to_owned.rs:121:30
    |
 LL |     require_as_ref_slice_str(array.to_owned(), s.to_owned());
    |                              ^^^^^^^^^^^^^^^^ help: use: `array`
 
 error: unnecessary use of `to_owned`
-  --> $DIR/unnecessary_to_owned.rs:122:48
+  --> $DIR/unnecessary_to_owned.rs:121:48
    |
 LL |     require_as_ref_slice_str(array.to_owned(), s.to_owned());
    |                                                ^^^^^^^^^^^^ help: use: `s`
 
 error: unnecessary use of `to_owned`
-  --> $DIR/unnecessary_to_owned.rs:123:30
+  --> $DIR/unnecessary_to_owned.rs:122:30
    |
 LL |     require_as_ref_slice_str(array_ref.to_owned(), s.to_owned());
    |                              ^^^^^^^^^^^^^^^^^^^^ help: use: `array_ref`
 
 error: unnecessary use of `to_owned`
-  --> $DIR/unnecessary_to_owned.rs:123:52
+  --> $DIR/unnecessary_to_owned.rs:122:52
    |
 LL |     require_as_ref_slice_str(array_ref.to_owned(), s.to_owned());
    |                                                    ^^^^^^^^^^^^ help: use: `s`
 
 error: unnecessary use of `to_owned`
-  --> $DIR/unnecessary_to_owned.rs:124:30
+  --> $DIR/unnecessary_to_owned.rs:123:30
    |
 LL |     require_as_ref_slice_str(slice.to_owned(), s.to_owned());
    |                              ^^^^^^^^^^^^^^^^ help: use: `slice`
 
 error: unnecessary use of `to_owned`
-  --> $DIR/unnecessary_to_owned.rs:124:48
+  --> $DIR/unnecessary_to_owned.rs:123:48
    |
 LL |     require_as_ref_slice_str(slice.to_owned(), s.to_owned());
    |                                                ^^^^^^^^^^^^ help: use: `s`
 
 error: unnecessary use of `to_string`
-  --> $DIR/unnecessary_to_owned.rs:126:20
+  --> $DIR/unnecessary_to_owned.rs:125:20
    |
 LL |     let _ = x.join(&x_ref.to_string());
    |                    ^^^^^^^^^^^^^^^^^^ help: use: `x_ref`
 
 error: unnecessary use of `to_vec`
-  --> $DIR/unnecessary_to_owned.rs:128:13
+  --> $DIR/unnecessary_to_owned.rs:127:13
    |
 LL |     let _ = slice.to_vec().into_iter();
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `slice.iter().copied()`
 
 error: unnecessary use of `to_owned`
-  --> $DIR/unnecessary_to_owned.rs:129:13
+  --> $DIR/unnecessary_to_owned.rs:128:13
    |
 LL |     let _ = slice.to_owned().into_iter();
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `slice.iter().copied()`
 
 error: unnecessary use of `to_vec`
-  --> $DIR/unnecessary_to_owned.rs:130:13
+  --> $DIR/unnecessary_to_owned.rs:129:13
    |
 LL |     let _ = [std::path::PathBuf::new()][..].to_vec().into_iter();
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `[std::path::PathBuf::new()][..].iter().cloned()`
 
 error: unnecessary use of `to_owned`
-  --> $DIR/unnecessary_to_owned.rs:131:13
+  --> $DIR/unnecessary_to_owned.rs:130:13
    |
 LL |     let _ = [std::path::PathBuf::new()][..].to_owned().into_iter();
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `[std::path::PathBuf::new()][..].iter().cloned()`
 
 error: unnecessary use of `to_vec`
-  --> $DIR/unnecessary_to_owned.rs:133:13
+  --> $DIR/unnecessary_to_owned.rs:132:13
    |
 LL |     let _ = IntoIterator::into_iter(slice.to_vec());
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `slice.iter().copied()`
 
 error: unnecessary use of `to_owned`
-  --> $DIR/unnecessary_to_owned.rs:134:13
+  --> $DIR/unnecessary_to_owned.rs:133:13
    |
 LL |     let _ = IntoIterator::into_iter(slice.to_owned());
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `slice.iter().copied()`
 
 error: unnecessary use of `to_vec`
-  --> $DIR/unnecessary_to_owned.rs:135:13
+  --> $DIR/unnecessary_to_owned.rs:134:13
    |
 LL |     let _ = IntoIterator::into_iter([std::path::PathBuf::new()][..].to_vec());
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `[std::path::PathBuf::new()][..].iter().cloned()`
 
 error: unnecessary use of `to_owned`
-  --> $DIR/unnecessary_to_owned.rs:136:13
+  --> $DIR/unnecessary_to_owned.rs:135:13
    |
 LL |     let _ = IntoIterator::into_iter([std::path::PathBuf::new()][..].to_owned());
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `[std::path::PathBuf::new()][..].iter().cloned()`
 
 error: unnecessary use of `to_vec`
-  --> $DIR/unnecessary_to_owned.rs:198:14
+  --> $DIR/unnecessary_to_owned.rs:197:14
    |
 LL |     for t in file_types.to_vec() {
    |              ^^^^^^^^^^^^^^^^^^^
@@ -492,25 +492,25 @@ LL +         let path = match get_file_path(t) {
    |
 
 error: unnecessary use of `to_vec`
-  --> $DIR/unnecessary_to_owned.rs:221:14
+  --> $DIR/unnecessary_to_owned.rs:220:14
    |
 LL |     let _ = &["x"][..].to_vec().into_iter();
    |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `["x"][..].iter().cloned()`
 
 error: unnecessary use of `to_vec`
-  --> $DIR/unnecessary_to_owned.rs:226:14
+  --> $DIR/unnecessary_to_owned.rs:225:14
    |
 LL |     let _ = &["x"][..].to_vec().into_iter();
    |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `["x"][..].iter().copied()`
 
 error: unnecessary use of `to_string`
-  --> $DIR/unnecessary_to_owned.rs:273:24
+  --> $DIR/unnecessary_to_owned.rs:272:24
    |
 LL |         Box::new(build(y.to_string()))
    |                        ^^^^^^^^^^^^^ help: use: `y`
 
 error: unnecessary use of `to_string`
-  --> $DIR/unnecessary_to_owned.rs:381:12
+  --> $DIR/unnecessary_to_owned.rs:380:12
    |
 LL |         id("abc".to_string())
    |            ^^^^^^^^^^^^^^^^^ help: use: `"abc"`
diff --git a/src/tools/clippy/tests/ui/unnecessary_unsafety_doc.rs b/src/tools/clippy/tests/ui/unnecessary_unsafety_doc.rs
new file mode 100644 (file)
index 0000000..c160e31
--- /dev/null
@@ -0,0 +1,149 @@
+// aux-build:doc_unsafe_macros.rs
+
+#![allow(clippy::let_unit_value)]
+#![warn(clippy::unnecessary_safety_doc)]
+
+#[macro_use]
+extern crate doc_unsafe_macros;
+
+/// This is has no safety section, and does not need one either
+pub fn destroy_the_planet() {
+    unimplemented!();
+}
+
+/// This one does not need a `Safety` section
+///
+/// # Safety
+///
+/// This function shouldn't be called unless the horsemen are ready
+pub fn apocalypse(universe: &mut ()) {
+    unimplemented!();
+}
+
+/// This is a private function, skip to match behavior with `missing_safety_doc`.
+///
+/// # Safety
+///
+/// Boo!
+fn you_dont_see_me() {
+    unimplemented!();
+}
+
+mod private_mod {
+    /// This is public but unexported function, skip to match behavior with `missing_safety_doc`.
+    ///
+    /// # Safety
+    ///
+    /// Very safe!
+    pub fn only_crate_wide_accessible() {
+        unimplemented!();
+    }
+
+    /// # Safety
+    ///
+    /// Unnecessary safety!
+    pub fn republished() {
+        unimplemented!();
+    }
+}
+
+pub use private_mod::republished;
+
+pub trait SafeTraitSafeMethods {
+    fn woefully_underdocumented(self);
+
+    /// # Safety
+    ///
+    /// Unnecessary!
+    fn documented(self);
+}
+
+pub trait SafeTrait {
+    fn method();
+}
+
+/// # Safety
+///
+/// Unnecessary!
+pub trait DocumentedSafeTrait {
+    fn method2();
+}
+
+pub struct Struct;
+
+impl SafeTraitSafeMethods for Struct {
+    fn woefully_underdocumented(self) {
+        // all is well
+    }
+
+    fn documented(self) {
+        // all is still well
+    }
+}
+
+impl SafeTrait for Struct {
+    fn method() {}
+}
+
+impl DocumentedSafeTrait for Struct {
+    fn method2() {}
+}
+
+impl Struct {
+    /// # Safety
+    ///
+    /// Unnecessary!
+    pub fn documented() -> Self {
+        unimplemented!();
+    }
+
+    pub fn undocumented(&self) {
+        unimplemented!();
+    }
+
+    /// Private, fine again to stay consistent with `missing_safety_doc`.
+    ///
+    /// # Safety
+    ///
+    /// Unnecessary!
+    fn private(&self) {
+        unimplemented!();
+    }
+}
+
+macro_rules! very_safe {
+    () => {
+        pub fn whee() {
+            unimplemented!()
+        }
+
+        /// # Safety
+        ///
+        /// Driving is very safe already!
+        pub fn drive() {
+            whee()
+        }
+    };
+}
+
+very_safe!();
+
+// we don't lint code from external macros
+undocd_safe!();
+
+fn main() {}
+
+// do not lint if any parent has `#[doc(hidden)]` attribute
+// see #7347
+#[doc(hidden)]
+pub mod __macro {
+    pub struct T;
+    impl T {
+        pub unsafe fn f() {}
+    }
+}
+
+/// # Implementation safety
+pub trait DocumentedSafeTraitWithImplementationHeader {
+    fn method();
+}
diff --git a/src/tools/clippy/tests/ui/unnecessary_unsafety_doc.stderr b/src/tools/clippy/tests/ui/unnecessary_unsafety_doc.stderr
new file mode 100644 (file)
index 0000000..72898c9
--- /dev/null
@@ -0,0 +1,51 @@
+error: safe function's docs have unnecessary `# Safety` section
+  --> $DIR/unnecessary_unsafety_doc.rs:19:1
+   |
+LL | pub fn apocalypse(universe: &mut ()) {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::unnecessary-safety-doc` implied by `-D warnings`
+
+error: safe function's docs have unnecessary `# Safety` section
+  --> $DIR/unnecessary_unsafety_doc.rs:45:5
+   |
+LL |     pub fn republished() {
+   |     ^^^^^^^^^^^^^^^^^^^^
+
+error: safe function's docs have unnecessary `# Safety` section
+  --> $DIR/unnecessary_unsafety_doc.rs:58:5
+   |
+LL |     fn documented(self);
+   |     ^^^^^^^^^^^^^^^^^^^^
+
+error: docs for safe trait have unnecessary `# Safety` section
+  --> $DIR/unnecessary_unsafety_doc.rs:68:1
+   |
+LL | pub trait DocumentedSafeTrait {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: safe function's docs have unnecessary `# Safety` section
+  --> $DIR/unnecessary_unsafety_doc.rs:96:5
+   |
+LL |     pub fn documented() -> Self {
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: safe function's docs have unnecessary `# Safety` section
+  --> $DIR/unnecessary_unsafety_doc.rs:123:9
+   |
+LL |         pub fn drive() {
+   |         ^^^^^^^^^^^^^^
+...
+LL | very_safe!();
+   | ------------ in this macro invocation
+   |
+   = note: this error originates in the macro `very_safe` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: docs for safe trait have unnecessary `# Safety` section
+  --> $DIR/unnecessary_unsafety_doc.rs:147:1
+   |
+LL | pub trait DocumentedSafeTraitWithImplementationHeader {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 7 previous errors
+
index 9786c7b12128ba811fb0298222d3e48b821eed9f..0a8e7b34dfa4fcdd622b742c45b94a1b3d7ae939 100644 (file)
@@ -1,6 +1,6 @@
 // run-rustfix
 
-#![feature(box_patterns, custom_inner_attributes)]
+#![feature(box_patterns)]
 #![warn(clippy::unnested_or_patterns)]
 #![allow(clippy::cognitive_complexity, clippy::match_ref_pats, clippy::upper_case_acronyms)]
 #![allow(unreachable_patterns, irrefutable_let_patterns, unused)]
@@ -34,14 +34,12 @@ fn main() {
     if let S { x: 0, y, .. } | S { y, x: 1 } = (S { x: 0, y: 1 }) {}
 }
 
+#[clippy::msrv = "1.52"]
 fn msrv_1_52() {
-    #![clippy::msrv = "1.52"]
-
     if let [1] | [52] = [0] {}
 }
 
+#[clippy::msrv = "1.53"]
 fn msrv_1_53() {
-    #![clippy::msrv = "1.53"]
-
     if let [1 | 53] = [0] {}
 }
index f57322396d4ac242c09efab9a7c9bdde7e8779cb..2c454adfe89db0066ebd5df473c9c0c898005524 100644 (file)
@@ -1,6 +1,6 @@
 // run-rustfix
 
-#![feature(box_patterns, custom_inner_attributes)]
+#![feature(box_patterns)]
 #![warn(clippy::unnested_or_patterns)]
 #![allow(clippy::cognitive_complexity, clippy::match_ref_pats, clippy::upper_case_acronyms)]
 #![allow(unreachable_patterns, irrefutable_let_patterns, unused)]
@@ -34,14 +34,12 @@ struct S {
     if let S { x: 0, y, .. } | S { y, x: 1 } = (S { x: 0, y: 1 }) {}
 }
 
+#[clippy::msrv = "1.52"]
 fn msrv_1_52() {
-    #![clippy::msrv = "1.52"]
-
     if let [1] | [52] = [0] {}
 }
 
+#[clippy::msrv = "1.53"]
 fn msrv_1_53() {
-    #![clippy::msrv = "1.53"]
-
     if let [1] | [53] = [0] {}
 }
index fbc12fff0b0e7dccc8d4c89aab51a408b499ea83..a1f193db555ad12f26fc5729490ec59d454b5758 100644 (file)
@@ -176,7 +176,7 @@ LL |     if let S { x: 0 | 1, y } = (S { x: 0, y: 1 }) {}
    |            ~~~~~~~~~~~~~~~~~
 
 error: unnested or-patterns
-  --> $DIR/unnested_or_patterns.rs:46:12
+  --> $DIR/unnested_or_patterns.rs:44:12
    |
 LL |     if let [1] | [53] = [0] {}
    |            ^^^^^^^^^^
index 38fe6c34cfec177e90a1f644cc215a200e476ceb..f6f734c05ed59e95c06401d13f7faa393c4a9051 100644 (file)
@@ -11,4 +11,7 @@ fn main() {
     let _ = 3.3_f32.round();
     let _ = 3.3_f64.round();
     let _ = 3.0_f32;
+
+    let _ = 3_3.0_0_f32;
+    let _ = 3_3.0_1_f64.round();
 }
index a5cac64d023ae1db417a8ac95f61436cee6e5cb8..a0267d8144aabb45c462280e45bb29f46ed81d03 100644 (file)
@@ -11,4 +11,7 @@ fn main() {
     let _ = 3.3_f32.round();
     let _ = 3.3_f64.round();
     let _ = 3.0_f32.round();
+
+    let _ = 3_3.0_0_f32.round();
+    let _ = 3_3.0_1_f64.round();
 }
index 1eeb5d1de883212f1dcc1aa25a3a4c21defbca5d..b867996fe5763c826e375a948796bf45e9bd0b0b 100644 (file)
@@ -24,5 +24,11 @@ error: used the `round` method with a whole number float
 LL |     let _ = 3.0_f32.round();
    |             ^^^^^^^^^^^^^^^ help: remove the `round` method call: `3.0_f32`
 
-error: aborting due to 4 previous errors
+error: used the `round` method with a whole number float
+  --> $DIR/unused_rounding.rs:15:13
+   |
+LL |     let _ = 3_3.0_0_f32.round();
+   |             ^^^^^^^^^^^^^^^^^^^ help: remove the `round` method call: `3_3.0_0_f32`
+
+error: aborting due to 5 previous errors
 
index 3b54fe9d5ff3d66e8d7074b7884a9367537e340d..0a6166571ebe38c3f5c4bab85661b346f9751937 100644 (file)
@@ -1,7 +1,6 @@
 // run-rustfix
 // aux-build:proc_macro_derive.rs
 
-#![feature(custom_inner_attributes)]
 #![warn(clippy::use_self)]
 #![allow(dead_code, unreachable_code)]
 #![allow(
@@ -619,9 +618,8 @@ mod issue6902 {
     }
 }
 
+#[clippy::msrv = "1.36"]
 fn msrv_1_36() {
-    #![clippy::msrv = "1.36"]
-
     enum E {
         A,
     }
@@ -635,9 +633,8 @@ fn msrv_1_36() {
     }
 }
 
+#[clippy::msrv = "1.37"]
 fn msrv_1_37() {
-    #![clippy::msrv = "1.37"]
-
     enum E {
         A,
     }
index bf87633cd2d8f1b675552f2af3b5fae37ad5f191..39c2b431f7fb95323766b0ed75ce269494881637 100644 (file)
@@ -1,7 +1,6 @@
 // run-rustfix
 // aux-build:proc_macro_derive.rs
 
-#![feature(custom_inner_attributes)]
 #![warn(clippy::use_self)]
 #![allow(dead_code, unreachable_code)]
 #![allow(
@@ -619,9 +618,8 @@ pub enum Foo {
     }
 }
 
+#[clippy::msrv = "1.36"]
 fn msrv_1_36() {
-    #![clippy::msrv = "1.36"]
-
     enum E {
         A,
     }
@@ -635,9 +633,8 @@ fn foo(self) {
     }
 }
 
+#[clippy::msrv = "1.37"]
 fn msrv_1_37() {
-    #![clippy::msrv = "1.37"]
-
     enum E {
         A,
     }
index 16fb0609242cbfea2724b8b548ef41f720898739..48364c40c3b26007ca5b0d6049d9fa8168df407d 100644 (file)
@@ -1,5 +1,5 @@
 error: unnecessary structure name repetition
-  --> $DIR/use_self.rs:23:21
+  --> $DIR/use_self.rs:22:21
    |
 LL |         fn new() -> Foo {
    |                     ^^^ help: use the applicable keyword: `Self`
@@ -7,247 +7,247 @@ LL |         fn new() -> Foo {
    = note: `-D clippy::use-self` implied by `-D warnings`
 
 error: unnecessary structure name repetition
-  --> $DIR/use_self.rs:24:13
+  --> $DIR/use_self.rs:23:13
    |
 LL |             Foo {}
    |             ^^^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> $DIR/use_self.rs:26:22
+  --> $DIR/use_self.rs:25:22
    |
 LL |         fn test() -> Foo {
    |                      ^^^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> $DIR/use_self.rs:27:13
+  --> $DIR/use_self.rs:26:13
    |
 LL |             Foo::new()
    |             ^^^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> $DIR/use_self.rs:32:25
+  --> $DIR/use_self.rs:31:25
    |
 LL |         fn default() -> Foo {
    |                         ^^^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> $DIR/use_self.rs:33:13
+  --> $DIR/use_self.rs:32:13
    |
 LL |             Foo::new()
    |             ^^^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> $DIR/use_self.rs:98:24
+  --> $DIR/use_self.rs:97:24
    |
 LL |         fn bad(foos: &[Foo]) -> impl Iterator<Item = &Foo> {
    |                        ^^^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> $DIR/use_self.rs:98:55
+  --> $DIR/use_self.rs:97:55
    |
 LL |         fn bad(foos: &[Foo]) -> impl Iterator<Item = &Foo> {
    |                                                       ^^^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> $DIR/use_self.rs:113:13
+  --> $DIR/use_self.rs:112:13
    |
 LL |             TS(0)
    |             ^^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> $DIR/use_self.rs:148:29
+  --> $DIR/use_self.rs:147:29
    |
 LL |                 fn bar() -> Bar {
    |                             ^^^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> $DIR/use_self.rs:149:21
+  --> $DIR/use_self.rs:148:21
    |
 LL |                     Bar { foo: Foo {} }
    |                     ^^^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> $DIR/use_self.rs:160:21
+  --> $DIR/use_self.rs:159:21
    |
 LL |         fn baz() -> Foo {
    |                     ^^^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> $DIR/use_self.rs:161:13
+  --> $DIR/use_self.rs:160:13
    |
 LL |             Foo {}
    |             ^^^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> $DIR/use_self.rs:178:21
+  --> $DIR/use_self.rs:177:21
    |
 LL |             let _ = Enum::B(42);
    |                     ^^^^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> $DIR/use_self.rs:179:21
+  --> $DIR/use_self.rs:178:21
    |
 LL |             let _ = Enum::C { field: true };
    |                     ^^^^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> $DIR/use_self.rs:180:21
+  --> $DIR/use_self.rs:179:21
    |
 LL |             let _ = Enum::A;
    |                     ^^^^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> $DIR/use_self.rs:222:13
+  --> $DIR/use_self.rs:221:13
    |
 LL |             nested::A::fun_1();
    |             ^^^^^^^^^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> $DIR/use_self.rs:223:13
+  --> $DIR/use_self.rs:222:13
    |
 LL |             nested::A::A;
    |             ^^^^^^^^^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> $DIR/use_self.rs:225:13
+  --> $DIR/use_self.rs:224:13
    |
 LL |             nested::A {};
    |             ^^^^^^^^^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> $DIR/use_self.rs:244:13
+  --> $DIR/use_self.rs:243:13
    |
 LL |             TestStruct::from_something()
    |             ^^^^^^^^^^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> $DIR/use_self.rs:258:25
+  --> $DIR/use_self.rs:257:25
    |
 LL |         async fn g() -> S {
    |                         ^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> $DIR/use_self.rs:259:13
+  --> $DIR/use_self.rs:258:13
    |
 LL |             S {}
    |             ^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> $DIR/use_self.rs:263:16
+  --> $DIR/use_self.rs:262:16
    |
 LL |             &p[S::A..S::B]
    |                ^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> $DIR/use_self.rs:263:22
+  --> $DIR/use_self.rs:262:22
    |
 LL |             &p[S::A..S::B]
    |                      ^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> $DIR/use_self.rs:286:29
+  --> $DIR/use_self.rs:285:29
    |
 LL |         fn foo(value: T) -> Foo<T> {
    |                             ^^^^^^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> $DIR/use_self.rs:287:13
+  --> $DIR/use_self.rs:286:13
    |
 LL |             Foo::<T> { value }
    |             ^^^^^^^^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> $DIR/use_self.rs:459:13
+  --> $DIR/use_self.rs:458:13
    |
 LL |             A::new::<submod::B>(submod::B {})
    |             ^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> $DIR/use_self.rs:496:13
+  --> $DIR/use_self.rs:495:13
    |
 LL |             S2::new()
    |             ^^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> $DIR/use_self.rs:533:17
+  --> $DIR/use_self.rs:532:17
    |
 LL |                 Foo::Bar => unimplemented!(),
    |                 ^^^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> $DIR/use_self.rs:534:17
+  --> $DIR/use_self.rs:533:17
    |
 LL |                 Foo::Baz => unimplemented!(),
    |                 ^^^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> $DIR/use_self.rs:540:20
+  --> $DIR/use_self.rs:539:20
    |
 LL |             if let Foo::Bar = self {
    |                    ^^^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> $DIR/use_self.rs:564:17
+  --> $DIR/use_self.rs:563:17
    |
 LL |                 Something::Num(n) => *n,
    |                 ^^^^^^^^^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> $DIR/use_self.rs:565:17
+  --> $DIR/use_self.rs:564:17
    |
 LL |                 Something::TupleNums(n, _m) => *n,
    |                 ^^^^^^^^^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> $DIR/use_self.rs:566:17
+  --> $DIR/use_self.rs:565:17
    |
 LL |                 Something::StructNums { one, two: _ } => *one,
    |                 ^^^^^^^^^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> $DIR/use_self.rs:572:17
+  --> $DIR/use_self.rs:571:17
    |
 LL |                 crate::issue8845::Something::Num(n) => *n,
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> $DIR/use_self.rs:573:17
+  --> $DIR/use_self.rs:572:17
    |
 LL |                 crate::issue8845::Something::TupleNums(n, _m) => *n,
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> $DIR/use_self.rs:574:17
+  --> $DIR/use_self.rs:573:17
    |
 LL |                 crate::issue8845::Something::StructNums { one, two: _ } => *one,
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> $DIR/use_self.rs:590:17
+  --> $DIR/use_self.rs:589:17
    |
 LL |             let Foo(x) = self;
    |                 ^^^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> $DIR/use_self.rs:595:17
+  --> $DIR/use_self.rs:594:17
    |
 LL |             let crate::issue8845::Foo(x) = self;
    |                 ^^^^^^^^^^^^^^^^^^^^^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> $DIR/use_self.rs:602:17
+  --> $DIR/use_self.rs:601:17
    |
 LL |             let Bar { x, .. } = self;
    |                 ^^^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> $DIR/use_self.rs:607:17
+  --> $DIR/use_self.rs:606:17
    |
 LL |             let crate::issue8845::Bar { x, .. } = self;
    |                 ^^^^^^^^^^^^^^^^^^^^^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> $DIR/use_self.rs:648:17
+  --> $DIR/use_self.rs:645:17
    |
 LL |                 E::A => {},
    |                 ^ help: use the applicable keyword: `Self`
index 80c30393832c107b93b6c45b9033b3dbb9fd0799..acb476ee69628efc987a0785bae0ddb36ea85b46 100644 (file)
@@ -4,9 +4,26 @@ allow-unauthenticated = [
     "good-first-issue"
 ]
 
-[assign]
-
 # Allows shortcuts like `@rustbot ready`
 #
 # See https://github.com/rust-lang/triagebot/wiki/Shortcuts
 [shortcut]
+
+[autolabel."S-waiting-on-review"]
+new_pr = true
+
+[assign]
+contributing_url = "https://github.com/rust-lang/rust-clippy/blob/master/CONTRIBUTING.md"
+
+[assign.owners]
+"/.github" = ["@flip1995"]
+"*" = [
+    "@flip1995",
+    "@Manishearth",
+    "@llogiq",
+    "@giraffate",
+    "@xFrednet",
+    "@Alexendoo",
+    "@dswij",
+    "@Jarcho",
+]
diff --git a/src/tools/collect-license-metadata/Cargo.toml b/src/tools/collect-license-metadata/Cargo.toml
new file mode 100644 (file)
index 0000000..d0820cf
--- /dev/null
@@ -0,0 +1,10 @@
+[package]
+name = "collect-license-metadata"
+version = "0.1.0"
+edition = "2021"
+
+[dependencies]
+anyhow = "1.0.65"
+serde = { version = "1.0.147", features = ["derive"] }
+serde_json = "1.0.85"
+spdx-rs = "0.5.1"
diff --git a/src/tools/collect-license-metadata/src/licenses.rs b/src/tools/collect-license-metadata/src/licenses.rs
new file mode 100644 (file)
index 0000000..1c95b1b
--- /dev/null
@@ -0,0 +1,65 @@
+use std::collections::HashMap;
+
+const COPYRIGHT_PREFIXES: &[&str] = &["SPDX-FileCopyrightText:", "Copyright", "(c)", "(C)", "©"];
+
+pub(crate) struct LicensesInterner {
+    by_id: Vec<License>,
+    by_struct: HashMap<License, usize>,
+}
+
+impl LicensesInterner {
+    pub(crate) fn new() -> Self {
+        LicensesInterner { by_id: Vec::new(), by_struct: HashMap::new() }
+    }
+
+    pub(crate) fn intern(&mut self, mut license: License) -> LicenseId {
+        license.simplify();
+        if let Some(id) = self.by_struct.get(&license) {
+            LicenseId(*id)
+        } else {
+            let id = self.by_id.len();
+            self.by_id.push(license.clone());
+            self.by_struct.insert(license, id);
+            LicenseId(id)
+        }
+    }
+
+    pub(crate) fn resolve(&self, id: LicenseId) -> &License {
+        &self.by_id[id.0]
+    }
+}
+
+#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, serde::Serialize)]
+#[serde(transparent)]
+pub(crate) struct LicenseId(usize);
+
+#[derive(Clone, Hash, PartialEq, Eq, serde::Serialize)]
+pub(crate) struct License {
+    pub(crate) spdx: String,
+    pub(crate) copyright: Vec<String>,
+}
+
+impl License {
+    fn simplify(&mut self) {
+        self.remove_copyright_prefixes();
+        self.copyright.sort();
+        self.copyright.dedup();
+    }
+
+    fn remove_copyright_prefixes(&mut self) {
+        for copyright in &mut self.copyright {
+            let mut stripped = copyright.trim();
+            let mut previous_stripped;
+            loop {
+                previous_stripped = stripped;
+                for pattern in COPYRIGHT_PREFIXES {
+                    stripped = stripped.trim_start_matches(pattern).trim_start();
+                }
+                if stripped == previous_stripped {
+                    break;
+                }
+            }
+            *copyright = stripped.into();
+        }
+    }
+}
diff --git a/src/tools/collect-license-metadata/src/main.rs b/src/tools/collect-license-metadata/src/main.rs
new file mode 100644 (file)
index 0000000..ca2a6f4
--- /dev/null
@@ -0,0 +1,30 @@
+mod licenses;
+mod path_tree;
+mod reuse;
+
+use crate::licenses::LicensesInterner;
+use anyhow::Error;
+use std::path::PathBuf;
+
+fn main() -> Result<(), Error> {
+    let reuse_exe: PathBuf = std::env::var_os("REUSE_EXE").expect("Missing REUSE_EXE").into();
+    let dest: PathBuf = std::env::var_os("DEST").expect("Missing DEST").into();
+
+    let mut interner = LicensesInterner::new();
+    let paths = crate::reuse::collect(&reuse_exe, &mut interner)?;
+
+    let mut tree = crate::path_tree::build(paths);
+    tree.simplify();
+
+    if let Some(parent) = dest.parent() {
+        std::fs::create_dir_all(parent)?;
+    }
+    std::fs::write(
+        &dest,
+        &serde_json::to_vec_pretty(&serde_json::json!({
+            "files": crate::path_tree::expand_interned_licenses(tree, &interner),
+        }))?,
+    )?;
+
+    Ok(())
+}
diff --git a/src/tools/collect-license-metadata/src/path_tree.rs b/src/tools/collect-license-metadata/src/path_tree.rs
new file mode 100644 (file)
index 0000000..133ff68
--- /dev/null
@@ -0,0 +1,294 @@
+//! Tools like REUSE output per-file licensing information, but we need to condense it in the
+//! minimum amount of data that still represents the same licensing metadata. This module is
+//! responsible for that, by turning the list of paths into a tree and executing simplification
+//! passes over the tree to remove redundant information.
+
+use crate::licenses::{License, LicenseId, LicensesInterner};
+use std::collections::BTreeMap;
+use std::path::{Path, PathBuf};
+
+#[derive(serde::Serialize)]
+#[serde(rename_all = "kebab-case", tag = "type")]
+pub(crate) enum Node<L> {
+    Root { childs: Vec<Node<L>> },
+    Directory { name: PathBuf, childs: Vec<Node<L>>, license: Option<L> },
+    File { name: PathBuf, license: L },
+    FileGroup { names: Vec<PathBuf>, license: L },
+    Empty,
+}
+
+impl Node<LicenseId> {
+    pub(crate) fn simplify(&mut self) {
+        self.merge_directories();
+        self.collapse_in_licensed_directories();
+        self.merge_directory_licenses();
+        self.merge_file_groups();
+        self.remove_empty();
+    }
+
+    /// Initially, the build() function constructs a list of separate paths from the file
+    /// system root down to each file, like so:
+    ///
+    /// ```text
+    ///         â”Œâ”€â–º ./ â”€â”€â–º compiler/ â”€â”€â–º rustc/ â”€â”€â–º src/ â”€â”€â–º main.rs
+    ///         â”‚
+    /// <root> â”€â”¼â”€â–º ./ â”€â”€â–º compiler/ â”€â”€â–º rustc/ â”€â”€â–º Cargo.toml
+    ///         â”‚
+    ///         â””─► ./ â”€â”€â–º library/ â”€â”€â”€â–º std/ â”€â”€â–º Cargo.toml
+    /// ```
+    ///
+    /// This pass is responsible for turning that into a proper directory tree:
+    ///
+    /// ```text
+    ///                 â”Œâ”€â–º compiler/ â”€â”€â–º rustc/ â”€â”€â”¬â”€â–º src/ â”€â”€â–º main.rs
+    ///                 â”‚                          â”‚
+    /// <root> â”€â”€â–º ./ â”€â”€â”¤                          â””─► Cargo.toml
+    ///                 â”‚
+    ///                 â””─► library/ â”€â”€â”€â–º std/ â”€â”€â–º Cargo.toml
+    /// ```
+    fn merge_directories(&mut self) {
+        match self {
+            Node::Root { childs } | Node::Directory { childs, license: None, .. } => {
+                let mut directories = BTreeMap::new();
+                let mut files = Vec::new();
+
+                for child in childs.drain(..) {
+                    match child {
+                        Node::Directory { name, mut childs, license: None } => {
+                            directories.entry(name).or_insert_with(Vec::new).append(&mut childs);
+                        }
+                        file @ Node::File { .. } => {
+                            files.push(file);
+                        }
+                        Node::Empty => {}
+                        Node::Root { .. } => {
+                            panic!("can't have a root inside another element");
+                        }
+                        Node::FileGroup { .. } => {
+                            panic!("FileGroup should not be present at this stage");
+                        }
+                        Node::Directory { license: Some(_), .. } => {
+                            panic!("license should not be set at this stage");
+                        }
+                    }
+                }
+
+                childs.extend(directories.into_iter().map(|(name, childs)| Node::Directory {
+                    name,
+                    childs,
+                    license: None,
+                }));
+                childs.append(&mut files);
+
+                for child in &mut *childs {
+                    child.merge_directories();
+                }
+            }
+            Node::Empty => {}
+            Node::File { .. } => {}
+            Node::FileGroup { .. } => {
+                panic!("FileGroup should not be present at this stage");
+            }
+            Node::Directory { license: Some(_), .. } => {
+                panic!("license should not be set at this stage");
+            }
+        }
+    }
+
+    /// In our codebase, most files in a directory have the same license as the other files in that
+    /// same directory, so it's redundant to store licensing metadata for all the files. Instead,
+    /// we can add a license for a whole directory, and only record the exceptions to a directory
+    /// licensing metadata.
+    ///
+    /// We cannot instead record only the difference to Rust's standard licensing, as the majority
+    /// of the files in our repository are *not* licensed under Rust's standard licensing due to
+    /// our inclusion of LLVM.
+    fn collapse_in_licensed_directories(&mut self) {
+        match self {
+            Node::Directory { childs, license, .. } => {
+                for child in &mut *childs {
+                    child.collapse_in_licensed_directories();
+                }
+
+                let mut licenses_count = BTreeMap::new();
+                for child in &*childs {
+                    let Some(license) = child.license() else { continue };
+                    *licenses_count.entry(license).or_insert(0) += 1;
+                }
+
+                let most_popular_license = licenses_count
+                    .into_iter()
+                    .max_by_key(|(_, count)| *count)
+                    .map(|(license, _)| license);
+
+                if let Some(most_popular_license) = most_popular_license {
+                    childs.retain(|child| child.license() != Some(most_popular_license));
+                    *license = Some(most_popular_license);
+                }
+            }
+            Node::Root { childs } => {
+                for child in &mut *childs {
+                    child.collapse_in_licensed_directories();
+                }
+            }
+            Node::File { .. } => {}
+            Node::FileGroup { .. } => {}
+            Node::Empty => {}
+        }
+    }
+
+    /// Reduce the depth of the tree by merging subdirectories with the same license as their
+    /// parent directory into their parent, and adjusting the paths of the childs accordingly.
+    fn merge_directory_licenses(&mut self) {
+        match self {
+            Node::Root { childs } => {
+                for child in &mut *childs {
+                    child.merge_directory_licenses();
+                }
+            }
+            Node::Directory { childs, license, .. } => {
+                let mut to_add = Vec::new();
+                for child in &mut *childs {
+                    child.merge_directory_licenses();
+
+                    let Node::Directory {
+                        name: child_name,
+                        childs: child_childs,
+                        license: child_license,
+                    } = child else { continue };
+
+                    if child_license != license {
+                        continue;
+                    }
+                    for mut child_child in child_childs.drain(..) {
+                        match &mut child_child {
+                            Node::Root { .. } => {
+                                panic!("can't have a root inside another element");
+                            }
+                            Node::FileGroup { .. } => {
+                                panic!("FileGroup should not be present at this stage");
+                            }
+                            Node::Directory { name: child_child_name, .. } => {
+                                *child_child_name = child_name.join(&child_child_name);
+                            }
+                            Node::File { name: child_child_name, .. } => {
+                                *child_child_name = child_name.join(&child_child_name);
+                            }
+                            Node::Empty => {}
+                        }
+                        to_add.push(child_child);
+                    }
+
+                    *child = Node::Empty;
+                }
+                childs.append(&mut to_add);
+            }
+            Node::Empty => {}
+            Node::File { .. } => {}
+            Node::FileGroup { .. } => {}
+        }
+    }
+
+    /// This pass groups multiple files in a directory with the same license into a single
+    /// "FileGroup", so that the license of all those files can be reported as a group.
+    ///
+    /// Crucially this pass runs after collapse_in_licensed_directories, so the most common license
+    /// will already be marked as the directory's license and won't be turned into a group.
+    fn merge_file_groups(&mut self) {
+        match self {
+            Node::Root { childs } | Node::Directory { childs, .. } => {
+                let mut grouped = BTreeMap::new();
+
+                for child in &mut *childs {
+                    child.merge_file_groups();
+                    if let Node::File { name, license } = child {
+                        grouped.entry(*license).or_insert_with(Vec::new).push(name.clone());
+                        *child = Node::Empty;
+                    }
+                }
+
+                for (license, mut names) in grouped.into_iter() {
+                    if names.len() == 1 {
+                        childs.push(Node::File { license, name: names.pop().unwrap() });
+                    } else {
+                        childs.push(Node::FileGroup { license, names });
+                    }
+                }
+            }
+            Node::File { .. } => {}
+            Node::FileGroup { .. } => panic!("FileGroup should not be present at this stage"),
+            Node::Empty => {}
+        }
+    }
+
+    /// Some nodes were replaced with Node::Empty to mark them for deletion. As the last step, make
+    /// sure to remove them from the tree.
+    fn remove_empty(&mut self) {
+        match self {
+            Node::Root { childs } | Node::Directory { childs, .. } => {
+                for child in &mut *childs {
+                    child.remove_empty();
+                }
+                childs.retain(|child| !matches!(child, Node::Empty));
+            }
+            Node::FileGroup { .. } => {}
+            Node::File { .. } => {}
+            Node::Empty => {}
+        }
+    }
+
+    fn license(&self) -> Option<LicenseId> {
+        match self {
+            Node::Directory { childs, license: Some(license), .. } if childs.is_empty() => {
+                Some(*license)
+            }
+            Node::File { license, .. } => Some(*license),
+            _ => None,
+        }
+    }
+}
+
+pub(crate) fn build(mut input: Vec<(PathBuf, LicenseId)>) -> Node<LicenseId> {
+    let mut childs = Vec::new();
+
+    // Ensure reproducibility of all future steps.
+    input.sort();
+
+    for (path, license) in input {
+        let mut node = Node::File { name: path.file_name().unwrap().into(), license };
+        for component in path.parent().unwrap_or_else(|| Path::new(".")).components().rev() {
+            node = Node::Directory {
+                name: component.as_os_str().into(),
+                childs: vec![node],
+                license: None,
+            };
+        }
+
+        childs.push(node);
+    }
+
+    Node::Root { childs }
+}
+
+/// Convert a `Node<LicenseId>` into a `Node<&License>`, expanding all interned license IDs with a
+/// reference to the actual license metadata.
+pub(crate) fn expand_interned_licenses(
+    node: Node<LicenseId>,
+    interner: &LicensesInterner,
+) -> Node<&License> {
+    match node {
+        Node::Root { childs } => Node::Root {
+            childs: childs.into_iter().map(|child| strip_interning(child, interner)).collect(),
+        },
+        Node::Directory { name, childs, license } => Node::Directory {
+            childs: childs.into_iter().map(|child| strip_interning(child, interner)).collect(),
+            license: license.map(|license| interner.resolve(license)),
+            name,
+        },
+        Node::File { name, license } => Node::File { name, license: interner.resolve(license) },
+        Node::FileGroup { names, license } => {
+            Node::FileGroup { names, license: interner.resolve(license) }
+        }
+        Node::Empty => Node::Empty,
+    }
+}
diff --git a/src/tools/collect-license-metadata/src/reuse.rs b/src/tools/collect-license-metadata/src/reuse.rs
new file mode 100644 (file)
index 0000000..d6b3772
--- /dev/null
@@ -0,0 +1,49 @@
+use crate::licenses::{License, LicenseId, LicensesInterner};
+use anyhow::Error;
+use std::path::{Path, PathBuf};
+use std::process::{Command, Stdio};
+use std::time::Instant;
+
+pub(crate) fn collect(
+    reuse_exe: &Path,
+    interner: &mut LicensesInterner,
+) -> Result<Vec<(PathBuf, LicenseId)>, Error> {
+    eprintln!("gathering license information from REUSE");
+    let start = Instant::now();
+    let raw = &obtain_spdx_document(reuse_exe)?;
+    eprintln!("finished gathering the license information from REUSE in {:.2?}", start.elapsed());
+
+    let document = spdx_rs::parsers::spdx_from_tag_value(&raw)?;
+
+    let mut result = Vec::new();
+    for file in document.file_information {
+        let license = interner.intern(License {
+            spdx: file.concluded_license.to_string(),
+            copyright: file.copyright_text.split('\n').map(|s| s.into()).collect(),
+        });
+
+        result.push((file.file_name.into(), license));
+    }
+
+    Ok(result)
+}
+
+fn obtain_spdx_document(reuse_exe: &Path) -> Result<String, Error> {
+    let output = Command::new(reuse_exe)
+        .args(&["spdx", "--add-license-concluded", "--creator-person=bors"])
+        .stdout(Stdio::piped())
+        .spawn()?
+        .wait_with_output()?;
+
+    if !output.status.success() {
+        eprintln!();
+        eprintln!("Note that Rust requires some REUSE features that might not be present in the");
+        eprintln!("release you're using. Make sure your REUSE release includes these PRs:");
+        eprintln!();
+        eprintln!(" - https://github.com/fsfe/reuse-tool/pull/623");
+        eprintln!();
+        anyhow::bail!("collecting licensing information with REUSE failed");
+    }
+
+    Ok(String::from_utf8(output.stdout)?)
+}
index 0d9a629e179b8eb9df836be32426f467cfb3ce9d..c5767a795382e41a7af9413e8e30adc609b2c3ee 100644 (file)
@@ -260,9 +260,9 @@ pub fn from_file(testfile: &Path, cfg: Option<&str>, config: &Config) -> Self {
         props.load_from(testfile, cfg, config);
 
         match (props.pass_mode, props.fail_mode) {
-            (None, None) => props.fail_mode = Some(FailMode::Check),
-            (Some(_), None) | (None, Some(_)) => {}
+            (None, None) if config.mode == Mode::Ui => props.fail_mode = Some(FailMode::Check),
             (Some(_), Some(_)) => panic!("cannot use a *-fail and *-pass mode together"),
+            _ => {}
         }
 
         props
@@ -522,8 +522,8 @@ fn update_pass_mode(&mut self, ln: &str, revision: Option<&str>, config: &Config
     }
 
     pub fn pass_mode(&self, config: &Config) -> Option<PassMode> {
-        if !self.ignore_pass && self.fail_mode.is_none() && config.mode == Mode::Ui {
-            if let (mode @ Some(_), Some(_)) = (config.force_pass_mode, self.pass_mode) {
+        if !self.ignore_pass && self.fail_mode.is_none() {
+            if let mode @ Some(_) = config.force_pass_mode {
                 return mode;
             }
         }
@@ -906,6 +906,7 @@ pub fn make_test_description<R: Read>(
     let has_asm_support = config.has_asm_support();
     let has_asan = util::ASAN_SUPPORTED_TARGETS.contains(&&*config.target);
     let has_cfi = util::CFI_SUPPORTED_TARGETS.contains(&&*config.target);
+    let has_kcfi = util::KCFI_SUPPORTED_TARGETS.contains(&&*config.target);
     let has_lsan = util::LSAN_SUPPORTED_TARGETS.contains(&&*config.target);
     let has_msan = util::MSAN_SUPPORTED_TARGETS.contains(&&*config.target);
     let has_tsan = util::TSAN_SUPPORTED_TARGETS.contains(&&*config.target);
@@ -957,6 +958,7 @@ pub fn make_test_description<R: Read>(
             && config.parse_name_directive(ln, "needs-sanitizer-support");
         ignore |= !has_asan && config.parse_name_directive(ln, "needs-sanitizer-address");
         ignore |= !has_cfi && config.parse_name_directive(ln, "needs-sanitizer-cfi");
+        ignore |= !has_kcfi && config.parse_name_directive(ln, "needs-sanitizer-kcfi");
         ignore |= !has_lsan && config.parse_name_directive(ln, "needs-sanitizer-leak");
         ignore |= !has_msan && config.parse_name_directive(ln, "needs-sanitizer-memory");
         ignore |= !has_tsan && config.parse_name_directive(ln, "needs-sanitizer-thread");
index 519da685f940a24a6b18a2ab5780ad20db66146f..91c701a5ddd2e469b9115fc02af7eab28dd5349e 100644 (file)
@@ -514,6 +514,7 @@ pub fn test_opts(config: &Config) -> test::TestOpts {
         options: test::Options::new(),
         time_options: None,
         force_run_in_process: false,
+        fail_fast: std::env::var_os("RUSTC_TEST_FAIL_FAST").is_some(),
     }
 }
 
index e07b71a7c47802b07e5be842899be0f3706cb896..1542b1c17ad112006df87805d19e354b82bd6fc8 100644 (file)
@@ -3542,6 +3542,8 @@ fn normalize_output(&self, output: &str, custom_rules: &[(String, String)]) -> S
             option_env!("CFG_VIRTUAL_RUST_SOURCE_BASE_DIR").map(PathBuf::from),
             // Virtual `/rustc/$sha` coming from download-rustc:
             std::env::var_os("FAKE_DOWNLOAD_RUSTC_PREFIX").map(PathBuf::from),
+            // Tests using -Zsimulate-remapped-rust-src-base should use this fake path
+            Some("/rustc/FAKE_PREFIX".into()),
         ];
         for base_dir in source_bases {
             if let Some(base_dir) = base_dir {
index ec36f1e4fb72efd5beada293b800ad2aa4733404..ccba313ee357bf10c387f58cc99a8f5c6e5ceca2 100644 (file)
@@ -42,6 +42,8 @@
     "x86_64-unknown-netbsd",
 ];
 
+pub const KCFI_SUPPORTED_TARGETS: &[&str] = &["aarch64-linux-none", "x86_64-linux-none"];
+
 pub const LSAN_SUPPORTED_TARGETS: &[&str] = &[
     // FIXME: currently broken, see #88132
     // "aarch64-apple-darwin",
diff --git a/src/tools/generate-copyright/Cargo.toml b/src/tools/generate-copyright/Cargo.toml
new file mode 100644 (file)
index 0000000..899ef0f
--- /dev/null
@@ -0,0 +1,11 @@
+[package]
+name = "generate-copyright"
+version = "0.1.0"
+edition = "2021"
+
+# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+
+[dependencies]
+anyhow = "1.0.65"
+serde = { version = "1.0.147", features = ["derive"] }
+serde_json = "1.0.85"
diff --git a/src/tools/generate-copyright/src/main.rs b/src/tools/generate-copyright/src/main.rs
new file mode 100644 (file)
index 0000000..d172c9e
--- /dev/null
@@ -0,0 +1,94 @@
+use anyhow::Error;
+use std::io::Write;
+use std::path::PathBuf;
+
+fn main() -> Result<(), Error> {
+    let dest = env_path("DEST")?;
+    let license_metadata = env_path("LICENSE_METADATA")?;
+
+    let metadata: Metadata = serde_json::from_slice(&std::fs::read(&license_metadata)?)?;
+
+    let mut buffer = Vec::new();
+    render_recursive(&metadata.files, &mut buffer, 0)?;
+
+    std::fs::write(&dest, &buffer)?;
+
+    Ok(())
+}
+
+fn render_recursive(node: &Node, buffer: &mut Vec<u8>, depth: usize) -> Result<(), Error> {
+    let prefix = std::iter::repeat("> ").take(depth + 1).collect::<String>();
+
+    match node {
+        Node::Root { childs } => {
+            for child in childs {
+                render_recursive(child, buffer, depth)?;
+            }
+        }
+        Node::Directory { name, childs, license } => {
+            render_license(&prefix, std::iter::once(name), license, buffer)?;
+            if !childs.is_empty() {
+                writeln!(buffer, "{prefix}")?;
+                writeln!(buffer, "{prefix}*Exceptions:*")?;
+                for child in childs {
+                    writeln!(buffer, "{prefix}")?;
+                    render_recursive(child, buffer, depth + 1)?;
+                }
+            }
+        }
+        Node::FileGroup { names, license } => {
+            render_license(&prefix, names.iter(), license, buffer)?;
+        }
+        Node::File { name, license } => {
+            render_license(&prefix, std::iter::once(name), license, buffer)?;
+        }
+    }
+
+    Ok(())
+}
+
+fn render_license<'a>(
+    prefix: &str,
+    names: impl Iterator<Item = &'a String>,
+    license: &License,
+    buffer: &mut Vec<u8>,
+) -> Result<(), Error> {
+    for name in names {
+        writeln!(buffer, "{prefix}**`{name}`**  ")?;
+    }
+    writeln!(buffer, "{prefix}License: `{}`  ", license.spdx)?;
+    for (i, copyright) in license.copyright.iter().enumerate() {
+        let suffix = if i == license.copyright.len() - 1 { "" } else { "  " };
+        writeln!(buffer, "{prefix}Copyright: {copyright}{suffix}")?;
+    }
+
+    Ok(())
+}
+
+#[derive(serde::Deserialize)]
+struct Metadata {
+    files: Node,
+}
+
+#[derive(serde::Deserialize)]
+#[serde(rename_all = "kebab-case", tag = "type")]
+pub(crate) enum Node {
+    Root { childs: Vec<Node> },
+    Directory { name: String, childs: Vec<Node>, license: License },
+    File { name: String, license: License },
+    FileGroup { names: Vec<String>, license: License },
+}
+
+#[derive(serde::Deserialize)]
+struct License {
+    spdx: String,
+    copyright: Vec<String>,
+}
+
+fn env_path(var: &str) -> Result<PathBuf, Error> {
+    if let Some(var) = std::env::var_os(var) {
+        Ok(var.into())
+    } else {
+        anyhow::bail!("missing environment variable {var}")
+    }
+}
index 5046ab9c7cbc178dad6ffc7744e78e57f875b6c8..e15f5fe3ccc968d46d295534015c3831d0ebff85 100644 (file)
@@ -60,6 +60,8 @@ pub fn check_crate(&mut self) {
 
     fn check_item(&mut self, id: &'a Id) {
         if let Some(item) = &self.krate.index.get(id) {
+            item.links.values().for_each(|id| self.add_any_id(id));
+
             match &item.inner {
                 ItemEnum::Import(x) => self.check_import(x),
                 ItemEnum::Union(x) => self.check_union(x),
@@ -376,6 +378,10 @@ fn add_id_checked(&mut self, id: &'a Id, valid: fn(Kind) -> bool, expected: &str
         }
     }
 
+    fn add_any_id(&mut self, id: &'a Id) {
+        self.add_id_checked(id, |_| true, "any kind of item");
+    }
+
     fn add_field_id(&mut self, id: &'a Id) {
         self.add_id_checked(id, Kind::is_struct_field, "StructField");
     }
@@ -446,3 +452,6 @@ fn set_remove<T: Hash + Eq + Clone>(set: &mut HashSet<T>) -> Option<T> {
         None
     }
 }
+
+#[cfg(test)]
+mod tests;
diff --git a/src/tools/jsondoclint/src/validator/tests.rs b/src/tools/jsondoclint/src/validator/tests.rs
new file mode 100644 (file)
index 0000000..c4aeee9
--- /dev/null
@@ -0,0 +1,50 @@
+use std::collections::HashMap;
+
+use rustdoc_json_types::{Crate, Item, Visibility};
+
+use super::*;
+
+#[track_caller]
+fn check(krate: &Crate, errs: &[Error]) {
+    let mut validator = Validator::new(krate);
+    validator.check_crate();
+
+    assert_eq!(errs, &validator.errs[..]);
+}
+
+fn id(s: &str) -> Id {
+    Id(s.to_owned())
+}
+
+#[test]
+fn errors_on_missing_links() {
+    let k = Crate {
+        root: id("0"),
+        crate_version: None,
+        includes_private: false,
+        index: HashMap::from_iter([(
+            id("0"),
+            Item {
+                name: Some("root".to_owned()),
+                id: id(""),
+                crate_id: 0,
+                span: None,
+                visibility: Visibility::Public,
+                docs: None,
+                links: HashMap::from_iter([("Not Found".to_owned(), id("1"))]),
+                attrs: vec![],
+                deprecation: None,
+                inner: ItemEnum::Module(Module {
+                    is_crate: true,
+                    items: vec![],
+                    is_stripped: false,
+                }),
+            },
+        )]),
+        paths: HashMap::new(),
+        external_crates: HashMap::new(),
+        format_version: rustdoc_json_types::FORMAT_VERSION,
+    };
+
+    check(&k, &[Error { kind: ErrorKind::NotFound, id: id("1") }]);
+}
index c63f356607d0750a1406053fa1a0250d3c3fd424..9d61cc4e2d5f0f0a686ef639e5940e5ed49ba777 100644 (file)
@@ -203,65 +203,32 @@ for more information about configuring VS Code and `rust-analyzer`.
 
 [rdg-r-a]: https://rustc-dev-guide.rust-lang.org/building/suggested.html#configuring-rust-analyzer-for-rustc
 
-## Advanced topic: other build environments
+## Advanced topic: Working on Miri in the rustc tree
 
 We described above the simplest way to get a working build environment for Miri,
 which is to use the version of rustc indicated by `rustc-version`. But
 sometimes, that is not enough.
 
-### Building Miri with a locally built rustc
+A big part of the Miri driver is shared with rustc, so working on Miri will
+sometimes require also working on rustc itself. In this case, you should *not*
+work in a clone of the Miri repository, but in a clone of the
+[main Rust repository](https://github.com/rust-lang/rust/). There is a copy of
+Miri located at `src/tools/miri` that you can work on directly. A maintainer
+will eventually sync those changes back into this repository.
 
-[building Miri with a locally built rustc]: #building-miri-with-a-locally-built-rustc
+When working on Miri in the rustc tree, here's how you can run tests:
 
-A big part of the Miri driver lives in rustc, so working on Miri will sometimes
-require using a locally built rustc. The bug you want to fix may actually be on
-the rustc side, or you just need to get more detailed trace of the execution
-than what is possible with release builds -- in both cases, you should develop
-Miri against a rustc you compiled yourself, with debug assertions (and hence
-tracing) enabled.
-
-The setup for a local rustc works as follows:
-```sh
-# Clone the rust-lang/rust repo.
-git clone https://github.com/rust-lang/rust rustc
-cd rustc
-# Create a config.toml with defaults for working on Miri.
-./x.py setup compiler
- # Now edit `config.toml` and under `[rust]` set `debug-assertions = true`.
-
-# Build a stage 2 rustc, and build the rustc libraries with that rustc.
-# This step can take 30 minutes or more.
-./x.py build --stage 2 compiler/rustc
-# If you change something, you can get a faster rebuild by doing
-./x.py build --keep-stage 0 --stage 2 compiler/rustc
-# You may have to change the architecture in the next command
-rustup toolchain link stage2 build/x86_64-unknown-linux-gnu/stage2
-# Now cd to your Miri directory, then configure rustup
-rustup override set stage2
 ```
-
-Note: When you are working with a locally built rustc or any other toolchain that
-is not the same as the one in `rust-version`, you should not have `.auto-everything` or
-`.auto-toolchain` as that will keep resetting your toolchain.
-
-```sh
-rm -f .auto-everything .auto-toolchain
+./x.py test miri --stage 0
 ```
 
-Important: You need to delete the Miri cache when you change the stdlib; otherwise the
-old, chached version will be used. On Linux, the cache is located at `~/.cache/miri`,
-and on Windows, it is located at `%LOCALAPPDATA%\rust-lang\miri\cache`; the exact
-location is printed after the library build: "A libstd for Miri is now available in ...".
-
-Note: `./x.py --stage 2 compiler/rustc` currently errors with `thread 'main'
-panicked at 'fs::read(stamp) failed with No such file or directory (os error 2)`,
-you can simply ignore that error; Miri will build anyway.
+`--bless` will work, too.
 
-For more information about building and configuring a local compiler,
-see <https://rustc-dev-guide.rust-lang.org/building/how-to-build-and-run.html>.
+You can also directly run Miri on a Rust source file:
 
-With this, you should now have a working development setup! See
-[above](#building-and-testing-miri) for how to proceed working on Miri.
+```
+./x.py run miri --stage 0 --args src/tools/miri/tests/pass/hello.rs
+```
 
 ## Advanced topic: Syncing with the rustc repo
 
index 15fc89b86818ac6cbb72e3d954c2c899e3c09fe1..876d49257caa5beb283092fddea261457706a970 100644 (file)
@@ -724,9 +724,9 @@ dependencies = [
 
 [[package]]
 name = "ui_test"
-version = "0.4.0"
+version = "0.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bf4559da3fe6b481f8674a29379677cb9606cd6f75fc254a2c9834c55638503d"
+checksum = "54ddb6f31025943e2f9d59237f433711c461a43d9415974c3eb3a4902edc1c1f"
 dependencies = [
  "bstr",
  "cargo_metadata",
index 0f69a0baef4fb29fae46fbe6348129515b294a66..717020f43c4f0c869c0432ffbdbfdfa8080c05af 100644 (file)
@@ -39,7 +39,7 @@ libloading = "0.7"
 
 [dev-dependencies]
 colored = "2"
-ui_test = "0.4"
+ui_test = "0.5"
 rustc_version = "0.4"
 # Features chosen to match those required by env_logger, to avoid rebuilds
 regex = { version = "1.5.5", default-features = false, features = ["perf", "std"] }
index 64b3187305e1af975c2c8a823d038f7cb20280d7..2bffff47722704d7b863b4a5aa6ea7ec0024a6c5 100644 (file)
@@ -94,7 +94,7 @@ pub fn phase_cargo_miri(mut args: impl Iterator<Item = String>) {
     let target = target.as_ref().unwrap_or(host);
 
     // We always setup.
-    setup(&subcommand, target, &rustc_version);
+    setup(&subcommand, target, &rustc_version, verbose);
 
     // Invoke actual cargo for the job, but with different flags.
     // We re-use `cargo test` and `cargo run`, which makes target and binary handling very easy but
@@ -486,8 +486,7 @@ pub fn phase_runner(mut binary_args: impl Iterator<Item = String>, phase: Runner
                 continue;
             } else if verbose > 0 {
                 eprintln!(
-                    "[cargo-miri runner] Overwriting run-time env var {:?}={:?} with build-time value {:?}",
-                    name, old_val, val
+                    "[cargo-miri runner] Overwriting run-time env var {name:?}={old_val:?} with build-time value {val:?}"
                 );
             }
         }
index 9c179e82ba1370fe3c758a366fbac01e68a5b44a..a696546954f90b9b3450aeb4610784cd1139742d 100644 (file)
@@ -13,7 +13,7 @@
 /// Performs the setup required to make `cargo miri` work: Getting a custom-built libstd. Then sets
 /// `MIRI_SYSROOT`. Skipped if `MIRI_SYSROOT` is already set, in which case we expect the user has
 /// done all this already.
-pub fn setup(subcommand: &MiriCommand, target: &str, rustc_version: &VersionMeta) {
+pub fn setup(subcommand: &MiriCommand, target: &str, rustc_version: &VersionMeta, verbose: usize) {
     let only_setup = matches!(subcommand, MiriCommand::Setup);
     let ask_user = !only_setup;
     let print_sysroot = only_setup && has_arg_flag("--print-sysroot"); // whether we just print the sysroot path
@@ -99,12 +99,13 @@ pub fn setup(subcommand: &MiriCommand, target: &str, rustc_version: &VersionMeta
         // `config.toml`.
         command.env("RUSTC_WRAPPER", "");
 
-        if only_setup {
-            if print_sysroot {
-                // Be extra sure there is no noise on stdout.
-                command.stdout(process::Stdio::null());
+        if only_setup && !print_sysroot {
+            // Forward output. Even make it verbose, if requested.
+            for _ in 0..verbose {
+                command.arg("-v");
             }
         } else {
+            // Supress output.
             command.stdout(process::Stdio::null());
             command.stderr(process::Stdio::null());
         }
@@ -120,7 +121,9 @@ pub fn setup(subcommand: &MiriCommand, target: &str, rustc_version: &VersionMeta
     std::env::set_var("MIRI_SYSROOT", &sysroot_dir);
 
     // Do the build.
-    if only_setup {
+    if print_sysroot {
+        // Be silent.
+    } else if only_setup {
         // We want to be explicit.
         eprintln!("Preparing a sysroot for Miri (target: {target})...");
     } else {
@@ -143,7 +146,9 @@ pub fn setup(subcommand: &MiriCommand, target: &str, rustc_version: &VersionMeta
                 )
             }
         });
-    if only_setup {
+    if print_sysroot {
+        // Be silent.
+    } else if only_setup {
         eprintln!("A sysroot for Miri is now available in `{}`.", sysroot_dir.display());
     } else {
         eprintln!("done");
index dd2d2abe35b539cff216bfabbd848718d8d3c8b1..e455b482338f4b7d4cd748b1bfa8f34f799e5ead 100755 (executable)
@@ -40,10 +40,15 @@ function run_tests {
   ./miri test
   if [ -z "${MIRI_TEST_TARGET+exists}" ]; then
     # Only for host architecture: tests with optimizations (`-O` is what cargo passes, but crank MIR
-    # optimizations up all the way).
-    # Optimizations change diagnostics (mostly backtraces), so we don't check them
-    #FIXME(#2155): we want to only run the pass and panic tests here, not the fail tests.
+    # optimizations up all the way, too).
+    # Optimizations change diagnostics (mostly backtraces), so we don't check
+    # them. Also error locations change so we don't run the failing tests.
     MIRIFLAGS="${MIRIFLAGS:-} -O -Zmir-opt-level=4" MIRI_SKIP_UI_CHECKS=1 ./miri test -- tests/{pass,panic}
+
+    # Also run some many-seeds tests. 64 seeds means this takes around a minute per test.
+    for FILE in tests/many-seeds/*.rs; do
+      MIRI_SEEDS=64 CARGO_EXTRA_FLAGS="$CARGO_EXTRA_FLAGS -q" ./miri many-seeds ./miri run "$FILE"
+    done
   fi
 
   ## test-cargo-miri
index 38d36898768e18c12f185a9e6966dcd86b55dd7f..a259576ed42a0edb8f2529f827a46ac216efa629 100755 (executable)
@@ -36,7 +36,8 @@ Mainly meant to be invoked by rust-analyzer.
 ./miri many-seeds <command>:
 Runs <command> over and over again with different seeds for Miri. The MIRIFLAGS
 variable is set to its original value appended with ` -Zmiri-seed=$SEED` for
-many different seeds.
+many different seeds. The MIRI_SEEDS variable controls how many seeds are being
+tried; MIRI_SEED_START controls the first seed to try.
 
 ./miri bench <benches>:
 Runs the benchmarks from bench-cargo-miri in hyperfine. hyperfine needs to be installed.
@@ -174,7 +175,9 @@ rustc-push)
     fi
     ;;
 many-seeds)
-    for SEED in $(seq 0 255); do
+    MIRI_SEED_START=${MIRI_SEED_START:-0} # default to 0
+    MIRI_SEEDS=${MIRI_SEEDS:-256} # default to 256
+    for SEED in $(seq $MIRI_SEED_START $(( $MIRI_SEED_START + $MIRI_SEEDS - 1 )) ); do
         echo "Trying seed: $SEED"
         MIRIFLAGS="$MIRIFLAGS -Zlayout-seed=$SEED -Zmiri-seed=$SEED" $@ || { echo "Failing seed: $SEED"; break; }
     done
@@ -249,6 +252,8 @@ export RUSTFLAGS="-C link-args=-Wl,-rpath,$LIBDIR $RUSTFLAGS"
 # Build a sysroot and set MIRI_SYSROOT to use it. Arguments are passed to `cargo miri setup`.
 build_sysroot() {
     if ! MIRI_SYSROOT="$($CARGO run $CARGO_EXTRA_FLAGS --manifest-path "$MIRIDIR"/cargo-miri/Cargo.toml -- miri setup --print-sysroot "$@")"; then
+        # Run it again so the user can see the error.
+        $CARGO run $CARGO_EXTRA_FLAGS --manifest-path "$MIRIDIR"/cargo-miri/Cargo.toml -- miri setup "$@"
         echo "'cargo miri setup' failed"
         exit 1
     fi
index 851ef39274094b6796e2e418de59f7e192fb0c64..8dd18ae98e6d62304a55fc6417ac2f021fbd4fef 100644 (file)
@@ -1 +1 @@
-454784afba5bf35b5ff14ada0e31265ad1d75e73
+203c8765ea33c65d888febe0e8219c4bb11b0d89
index ffe89921d98665219644fab5baa94bedb051c23b..fce95b987f729dc26c353bb8f7871905b6b57f3a 100644 (file)
@@ -192,10 +192,7 @@ fn init_late_loggers(tcx: TyCtxt<'_>) {
             if log::Level::from_str(&var).is_ok() {
                 env::set_var(
                     "RUSTC_LOG",
-                    format!(
-                        "rustc_middle::mir::interpret={0},rustc_const_eval::interpret={0}",
-                        var
-                    ),
+                    format!("rustc_middle::mir::interpret={var},rustc_const_eval::interpret={var}"),
                 );
             } else {
                 env::set_var("RUSTC_LOG", &var);
@@ -317,7 +314,7 @@ fn main() {
         } else if arg == "-Zmiri-disable-validation" {
             miri_config.validate = false;
         } else if arg == "-Zmiri-disable-stacked-borrows" {
-            miri_config.stacked_borrows = false;
+            miri_config.borrow_tracker = None;
         } else if arg == "-Zmiri-disable-data-race-detector" {
             miri_config.data_race_detector = false;
             miri_config.weak_memory_emulation = false;
@@ -413,7 +410,7 @@ fn main() {
                         err
                     ),
             };
-            for id in ids.into_iter().map(miri::SbTag::new) {
+            for id in ids.into_iter().map(miri::BorTag::new) {
                 if let Some(id) = id {
                     miri_config.tracked_pointer_tags.insert(id);
                 } else {
diff --git a/src/tools/miri/src/borrow_tracker/mod.rs b/src/tools/miri/src/borrow_tracker/mod.rs
new file mode 100644 (file)
index 0000000..f896a33
--- /dev/null
@@ -0,0 +1,378 @@
+use std::cell::RefCell;
+use std::fmt;
+use std::num::NonZeroU64;
+
+use log::trace;
+use smallvec::SmallVec;
+
+use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_middle::mir::RetagKind;
+use rustc_target::abi::Size;
+
+use crate::*;
+pub mod stacked_borrows;
+
+pub type CallId = NonZeroU64;
+
+/// Tracking pointer provenance
+#[derive(Copy, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
+pub struct BorTag(NonZeroU64);
+
+impl BorTag {
+    pub fn new(i: u64) -> Option<Self> {
+        NonZeroU64::new(i).map(BorTag)
+    }
+
+    pub fn get(&self) -> u64 {
+        self.0.get()
+    }
+
+    pub fn inner(&self) -> NonZeroU64 {
+        self.0
+    }
+
+    pub fn succ(self) -> Option<Self> {
+        self.0.checked_add(1).map(Self)
+    }
+
+    /// The minimum representable tag
+    pub fn one() -> Self {
+        Self::new(1).unwrap()
+    }
+}
+
+impl std::default::Default for BorTag {
+    /// The default to be used when borrow tracking is disabled
+    fn default() -> Self {
+        Self::one()
+    }
+}
+
+impl fmt::Debug for BorTag {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        write!(f, "<{}>", self.0)
+    }
+}
+
+/// Per-call-stack-frame data for borrow tracking
+#[derive(Debug)]
+pub struct FrameState {
+    /// The ID of the call this frame corresponds to.
+    pub call_id: CallId,
+
+    /// If this frame is protecting any tags, they are listed here. We use this list to do
+    /// incremental updates of the global list of protected tags stored in the
+    /// `stacked_borrows::GlobalState` upon function return, and if we attempt to pop a protected
+    /// tag, to identify which call is responsible for protecting the tag.
+    /// See `Stack::item_popped` for more explanation.
+    ///
+    /// This will contain one tag per reference passed to the function, so
+    /// a size of 2 is enough for the vast majority of functions.
+    pub protected_tags: SmallVec<[BorTag; 2]>,
+}
+
+impl VisitTags for FrameState {
+    fn visit_tags(&self, _visit: &mut dyn FnMut(BorTag)) {
+        // `protected_tags` are fine to GC.
+    }
+}
+
+/// Extra global state, available to the memory access hooks.
+#[derive(Debug)]
+pub struct GlobalStateInner {
+    /// Borrow tracker method currently in use.
+    pub borrow_tracker_method: BorrowTrackerMethod,
+    /// Next unused pointer ID (tag).
+    pub next_ptr_tag: BorTag,
+    /// Table storing the "base" tag for each allocation.
+    /// The base tag is the one used for the initial pointer.
+    /// We need this in a separate table to handle cyclic statics.
+    pub base_ptr_tags: FxHashMap<AllocId, BorTag>,
+    /// Next unused call ID (for protectors).
+    pub next_call_id: CallId,
+    /// All currently protected tags.
+    /// An item is protected if its tag is in this set, *and* it has the "protected" bit set.
+    /// We add tags to this when they are created with a protector in `reborrow`, and
+    /// we remove tags from this when the call which is protecting them returns, in
+    /// `GlobalStateInner::end_call`. See `Stack::item_popped` for more details.
+    pub protected_tags: FxHashMap<BorTag, ProtectorKind>,
+    /// The pointer ids to trace
+    pub tracked_pointer_tags: FxHashSet<BorTag>,
+    /// The call ids to trace
+    pub tracked_call_ids: FxHashSet<CallId>,
+    /// Whether to recurse into datatypes when searching for pointers to retag.
+    pub retag_fields: RetagFields,
+}
+
+impl VisitTags for GlobalStateInner {
+    fn visit_tags(&self, _visit: &mut dyn FnMut(BorTag)) {
+        // The only candidate is base_ptr_tags, and that does not need visiting since we don't ever
+        // GC the bottommost tag.
+    }
+}
+
+/// We need interior mutable access to the global state.
+pub type GlobalState = RefCell<GlobalStateInner>;
+
+/// Indicates which kind of access is being performed.
+#[derive(Copy, Clone, Hash, PartialEq, Eq, Debug)]
+pub enum AccessKind {
+    Read,
+    Write,
+}
+
+impl fmt::Display for AccessKind {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        match self {
+            AccessKind::Read => write!(f, "read access"),
+            AccessKind::Write => write!(f, "write access"),
+        }
+    }
+}
+
+/// Policy on whether to recurse into fields to retag
+#[derive(Copy, Clone, Debug)]
+pub enum RetagFields {
+    /// Don't retag any fields.
+    No,
+    /// Retag all fields.
+    Yes,
+    /// Only retag fields of types with Scalar and ScalarPair layout,
+    /// to match the LLVM `noalias` we generate.
+    OnlyScalar,
+}
+
+/// The flavor of the protector.
+#[derive(Copy, Clone, Debug, PartialEq, Eq)]
+pub enum ProtectorKind {
+    /// Protected against aliasing violations from other pointers.
+    ///
+    /// Items protected like this cause UB when they are invalidated, *but* the pointer itself may
+    /// still be used to issue a deallocation.
+    ///
+    /// This is required for LLVM IR pointers that are `noalias` but *not* `dereferenceable`.
+    WeakProtector,
+
+    /// Protected against any kind of invalidation.
+    ///
+    /// Items protected like this cause UB when they are invalidated or the memory is deallocated.
+    /// This is strictly stronger protection than `WeakProtector`.
+    ///
+    /// This is required for LLVM IR pointers that are `dereferenceable` (and also allows `noalias`).
+    StrongProtector,
+}
+
+/// Utilities for initialization and ID generation
+impl GlobalStateInner {
+    pub fn new(
+        borrow_tracker_method: BorrowTrackerMethod,
+        tracked_pointer_tags: FxHashSet<BorTag>,
+        tracked_call_ids: FxHashSet<CallId>,
+        retag_fields: RetagFields,
+    ) -> Self {
+        GlobalStateInner {
+            borrow_tracker_method,
+            next_ptr_tag: BorTag::one(),
+            base_ptr_tags: FxHashMap::default(),
+            next_call_id: NonZeroU64::new(1).unwrap(),
+            protected_tags: FxHashMap::default(),
+            tracked_pointer_tags,
+            tracked_call_ids,
+            retag_fields,
+        }
+    }
+
+    /// Generates a new pointer tag. Remember to also check track_pointer_tags and log its creation!
+    pub fn new_ptr(&mut self) -> BorTag {
+        let id = self.next_ptr_tag;
+        self.next_ptr_tag = id.succ().unwrap();
+        id
+    }
+
+    pub fn new_frame(&mut self, machine: &MiriMachine<'_, '_>) -> FrameState {
+        let call_id = self.next_call_id;
+        trace!("new_frame: Assigning call ID {}", call_id);
+        if self.tracked_call_ids.contains(&call_id) {
+            machine.emit_diagnostic(NonHaltingDiagnostic::CreatedCallId(call_id));
+        }
+        self.next_call_id = NonZeroU64::new(call_id.get() + 1).unwrap();
+        FrameState { call_id, protected_tags: SmallVec::new() }
+    }
+
+    pub fn end_call(&mut self, frame: &machine::FrameExtra<'_>) {
+        for tag in &frame
+            .borrow_tracker
+            .as_ref()
+            .expect("we should have borrow tracking data")
+            .protected_tags
+        {
+            self.protected_tags.remove(tag);
+        }
+    }
+
+    pub fn base_ptr_tag(&mut self, id: AllocId, machine: &MiriMachine<'_, '_>) -> BorTag {
+        self.base_ptr_tags.get(&id).copied().unwrap_or_else(|| {
+            let tag = self.new_ptr();
+            if self.tracked_pointer_tags.contains(&tag) {
+                machine.emit_diagnostic(NonHaltingDiagnostic::CreatedPointerTag(
+                    tag.inner(),
+                    None,
+                    None,
+                ));
+            }
+            trace!("New allocation {:?} has base tag {:?}", id, tag);
+            self.base_ptr_tags.try_insert(id, tag).unwrap();
+            tag
+        })
+    }
+}
+
+/// Which borrow tracking method to use
+#[derive(Debug, Copy, Clone, PartialEq, Eq)]
+pub enum BorrowTrackerMethod {
+    /// Stacked Borrows, as implemented in borrow_tracker/stacked
+    StackedBorrows,
+}
+
+impl BorrowTrackerMethod {
+    pub fn instanciate_global_state(self, config: &MiriConfig) -> GlobalState {
+        RefCell::new(GlobalStateInner::new(
+            self,
+            config.tracked_pointer_tags.clone(),
+            config.tracked_call_ids.clone(),
+            config.retag_fields,
+        ))
+    }
+}
+
+impl GlobalStateInner {
+    pub fn new_allocation(
+        &mut self,
+        id: AllocId,
+        alloc_size: Size,
+        kind: MemoryKind<machine::MiriMemoryKind>,
+        machine: &MiriMachine<'_, '_>,
+    ) -> AllocState {
+        match self.borrow_tracker_method {
+            BorrowTrackerMethod::StackedBorrows =>
+                AllocState::StackedBorrows(Box::new(RefCell::new(Stacks::new_allocation(
+                    id, alloc_size, self, kind, machine,
+                )))),
+        }
+    }
+}
+
+impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriInterpCx<'mir, 'tcx> {}
+pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
+    fn retag_ptr_value(&mut self, kind: RetagKind, val: &ImmTy<'tcx, Provenance>) -> InterpResult<'tcx, ImmTy<'tcx, Provenance>> {
+        let this = self.eval_context_mut();
+        let method = this.machine.borrow_tracker.as_ref().unwrap().borrow().borrow_tracker_method;
+        match method {
+            BorrowTrackerMethod::StackedBorrows => this.sb_retag_ptr_value(kind, val),
+        }
+    }
+
+    fn retag_place_contents(&mut self, kind: RetagKind, place: &PlaceTy<'tcx, Provenance>) -> InterpResult<'tcx> {
+        let this = self.eval_context_mut();
+        let method = this.machine.borrow_tracker.as_ref().unwrap().borrow().borrow_tracker_method;
+        match method {
+            BorrowTrackerMethod::StackedBorrows => this.sb_retag_place_contents(kind, place),
+        }
+    }
+
+    fn retag_return_place(&mut self) -> InterpResult<'tcx> {
+        let this = self.eval_context_mut();
+        let method = this.machine.borrow_tracker.as_ref().unwrap().borrow().borrow_tracker_method;
+        match method {
+            BorrowTrackerMethod::StackedBorrows => this.sb_retag_return_place(),
+        }
+    }
+
+    fn expose_tag(&mut self, alloc_id: AllocId, tag: BorTag) -> InterpResult<'tcx> {
+        let this = self.eval_context_mut();
+        let method = this.machine.borrow_tracker.as_ref().unwrap().borrow().borrow_tracker_method;
+        match method {
+            BorrowTrackerMethod::StackedBorrows => this.sb_expose_tag(alloc_id, tag),
+        }
+    }
+}
+
+/// Extra per-allocation data for borrow tracking
+#[derive(Debug, Clone)]
+pub enum AllocState {
+    /// Data corresponding to Stacked Borrows
+    StackedBorrows(Box<RefCell<stacked_borrows::AllocState>>),
+}
+
+impl machine::AllocExtra {
+    #[track_caller]
+    pub fn borrow_tracker_sb(&self) -> &RefCell<stacked_borrows::AllocState> {
+        match self.borrow_tracker {
+            Some(AllocState::StackedBorrows(ref sb)) => sb,
+            _ => panic!("expected Stacked Borrows borrow tracking, got something else"),
+        }
+    }
+
+    #[track_caller]
+    pub fn borrow_tracker_sb_mut(&mut self) -> &mut RefCell<stacked_borrows::AllocState> {
+        match self.borrow_tracker {
+            Some(AllocState::StackedBorrows(ref mut sb)) => sb,
+            _ => panic!("expected Stacked Borrows borrow tracking, got something else"),
+        }
+    }
+}
+
+impl AllocState {
+    pub fn before_memory_read<'tcx>(
+        &self,
+        alloc_id: AllocId,
+        prov_extra: ProvenanceExtra,
+        range: AllocRange,
+        machine: &MiriMachine<'_, 'tcx>,
+    ) -> InterpResult<'tcx> {
+        match self {
+            AllocState::StackedBorrows(sb) =>
+                sb.borrow_mut().before_memory_read(alloc_id, prov_extra, range, machine),
+        }
+    }
+
+    pub fn before_memory_write<'tcx>(
+        &mut self,
+        alloc_id: AllocId,
+        prov_extra: ProvenanceExtra,
+        range: AllocRange,
+        machine: &mut MiriMachine<'_, 'tcx>,
+    ) -> InterpResult<'tcx> {
+        match self {
+            AllocState::StackedBorrows(sb) =>
+                sb.get_mut().before_memory_write(alloc_id, prov_extra, range, machine),
+        }
+    }
+
+    pub fn before_memory_deallocation<'tcx>(
+        &mut self,
+        alloc_id: AllocId,
+        prov_extra: ProvenanceExtra,
+        range: AllocRange,
+        machine: &mut MiriMachine<'_, 'tcx>,
+    ) -> InterpResult<'tcx> {
+        match self {
+            AllocState::StackedBorrows(sb) =>
+                sb.get_mut().before_memory_deallocation(alloc_id, prov_extra, range, machine),
+        }
+    }
+
+    pub fn remove_unreachable_tags(&self, tags: &FxHashSet<BorTag>) {
+        match self {
+            AllocState::StackedBorrows(sb) => sb.borrow_mut().remove_unreachable_tags(tags),
+        }
+    }
+}
+
+impl VisitTags for AllocState {
+    fn visit_tags(&self, visit: &mut dyn FnMut(BorTag)) {
+        match self {
+            AllocState::StackedBorrows(sb) => sb.visit_tags(visit),
+        }
+    }
+}
diff --git a/src/tools/miri/src/borrow_tracker/stacked_borrows/diagnostics.rs b/src/tools/miri/src/borrow_tracker/stacked_borrows/diagnostics.rs
new file mode 100644 (file)
index 0000000..24b3489
--- /dev/null
@@ -0,0 +1,502 @@
+use smallvec::SmallVec;
+use std::fmt;
+
+use rustc_middle::mir::interpret::{alloc_range, AllocId, AllocRange, InterpError};
+use rustc_span::{Span, SpanData};
+use rustc_target::abi::Size;
+
+use crate::borrow_tracker::{
+    stacked_borrows::{err_sb_ub, Permission},
+    AccessKind, GlobalStateInner, ProtectorKind,
+};
+use crate::*;
+
+#[derive(Clone, Debug)]
+pub struct AllocHistory {
+    id: AllocId,
+    base: (Item, Span),
+    creations: smallvec::SmallVec<[Creation; 1]>,
+    invalidations: smallvec::SmallVec<[Invalidation; 1]>,
+    protectors: smallvec::SmallVec<[Protection; 1]>,
+}
+
+#[derive(Clone, Debug)]
+struct Creation {
+    retag: RetagOp,
+    span: Span,
+}
+
+impl Creation {
+    fn generate_diagnostic(&self) -> (String, SpanData) {
+        let tag = self.retag.new_tag;
+        if let Some(perm) = self.retag.permission {
+            (
+                format!(
+                    "{tag:?} was created by a {:?} retag at offsets {:?}",
+                    perm, self.retag.range,
+                ),
+                self.span.data(),
+            )
+        } else {
+            assert!(self.retag.range.size == Size::ZERO);
+            (
+                format!(
+                    "{tag:?} would have been created here, but this is a zero-size retag ({:?}) so the tag in question does not exist anywhere",
+                    self.retag.range,
+                ),
+                self.span.data(),
+            )
+        }
+    }
+}
+
+#[derive(Clone, Debug)]
+struct Invalidation {
+    tag: BorTag,
+    range: AllocRange,
+    span: Span,
+    cause: InvalidationCause,
+}
+
+#[derive(Clone, Debug)]
+enum InvalidationCause {
+    Access(AccessKind),
+    Retag(Permission, RetagCause),
+}
+
+impl Invalidation {
+    fn generate_diagnostic(&self) -> (String, SpanData) {
+        let message = if let InvalidationCause::Retag(_, RetagCause::FnEntry) = self.cause {
+            // For a FnEntry retag, our Span points at the caller.
+            // See `DiagnosticCx::log_invalidation`.
+            format!(
+                "{:?} was later invalidated at offsets {:?} by a {} inside this call",
+                self.tag, self.range, self.cause
+            )
+        } else {
+            format!(
+                "{:?} was later invalidated at offsets {:?} by a {}",
+                self.tag, self.range, self.cause
+            )
+        };
+        (message, self.span.data())
+    }
+}
+
+impl fmt::Display for InvalidationCause {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        match self {
+            InvalidationCause::Access(kind) => write!(f, "{kind}"),
+            InvalidationCause::Retag(perm, kind) =>
+                if *kind == RetagCause::FnEntry {
+                    write!(f, "{perm:?} FnEntry retag")
+                } else {
+                    write!(f, "{perm:?} retag")
+                },
+        }
+    }
+}
+
+#[derive(Clone, Debug)]
+struct Protection {
+    tag: BorTag,
+    span: Span,
+}
+
+#[derive(Clone)]
+pub struct TagHistory {
+    pub created: (String, SpanData),
+    pub invalidated: Option<(String, SpanData)>,
+    pub protected: Option<(String, SpanData)>,
+}
+
+pub struct DiagnosticCxBuilder<'ecx, 'mir, 'tcx> {
+    operation: Operation,
+    machine: &'ecx MiriMachine<'mir, 'tcx>,
+}
+
+pub struct DiagnosticCx<'history, 'ecx, 'mir, 'tcx> {
+    operation: Operation,
+    machine: &'ecx MiriMachine<'mir, 'tcx>,
+    history: &'history mut AllocHistory,
+    offset: Size,
+}
+
+impl<'ecx, 'mir, 'tcx> DiagnosticCxBuilder<'ecx, 'mir, 'tcx> {
+    pub fn build<'history>(
+        self,
+        history: &'history mut AllocHistory,
+        offset: Size,
+    ) -> DiagnosticCx<'history, 'ecx, 'mir, 'tcx> {
+        DiagnosticCx { operation: self.operation, machine: self.machine, history, offset }
+    }
+
+    pub fn retag(
+        machine: &'ecx MiriMachine<'mir, 'tcx>,
+        cause: RetagCause,
+        new_tag: BorTag,
+        orig_tag: ProvenanceExtra,
+        range: AllocRange,
+    ) -> Self {
+        let operation =
+            Operation::Retag(RetagOp { cause, new_tag, orig_tag, range, permission: None });
+
+        DiagnosticCxBuilder { machine, operation }
+    }
+
+    pub fn read(
+        machine: &'ecx MiriMachine<'mir, 'tcx>,
+        tag: ProvenanceExtra,
+        range: AllocRange,
+    ) -> Self {
+        let operation = Operation::Access(AccessOp { kind: AccessKind::Read, tag, range });
+        DiagnosticCxBuilder { machine, operation }
+    }
+
+    pub fn write(
+        machine: &'ecx MiriMachine<'mir, 'tcx>,
+        tag: ProvenanceExtra,
+        range: AllocRange,
+    ) -> Self {
+        let operation = Operation::Access(AccessOp { kind: AccessKind::Write, tag, range });
+        DiagnosticCxBuilder { machine, operation }
+    }
+
+    pub fn dealloc(machine: &'ecx MiriMachine<'mir, 'tcx>, tag: ProvenanceExtra) -> Self {
+        let operation = Operation::Dealloc(DeallocOp { tag });
+        DiagnosticCxBuilder { machine, operation }
+    }
+}
+
+impl<'history, 'ecx, 'mir, 'tcx> DiagnosticCx<'history, 'ecx, 'mir, 'tcx> {
+    pub fn unbuild(self) -> DiagnosticCxBuilder<'ecx, 'mir, 'tcx> {
+        DiagnosticCxBuilder { machine: self.machine, operation: self.operation }
+    }
+}
+
+#[derive(Debug, Clone)]
+enum Operation {
+    Retag(RetagOp),
+    Access(AccessOp),
+    Dealloc(DeallocOp),
+}
+
+#[derive(Debug, Clone)]
+struct RetagOp {
+    cause: RetagCause,
+    new_tag: BorTag,
+    orig_tag: ProvenanceExtra,
+    range: AllocRange,
+    permission: Option<Permission>,
+}
+
+#[derive(Debug, Clone, Copy, PartialEq)]
+pub enum RetagCause {
+    Normal,
+    FnReturn,
+    FnEntry,
+    TwoPhase,
+}
+
+#[derive(Debug, Clone)]
+struct AccessOp {
+    kind: AccessKind,
+    tag: ProvenanceExtra,
+    range: AllocRange,
+}
+
+#[derive(Debug, Clone)]
+struct DeallocOp {
+    tag: ProvenanceExtra,
+}
+
+impl AllocHistory {
+    pub fn new(id: AllocId, item: Item, machine: &MiriMachine<'_, '_>) -> Self {
+        Self {
+            id,
+            base: (item, machine.current_span()),
+            creations: SmallVec::new(),
+            invalidations: SmallVec::new(),
+            protectors: SmallVec::new(),
+        }
+    }
+}
+
+impl<'history, 'ecx, 'mir, 'tcx> DiagnosticCx<'history, 'ecx, 'mir, 'tcx> {
+    pub fn start_grant(&mut self, perm: Permission) {
+        let Operation::Retag(op) = &mut self.operation else {
+            unreachable!("start_grant must only be called during a retag, this is: {:?}", self.operation)
+        };
+        op.permission = Some(perm);
+
+        let last_creation = &mut self.history.creations.last_mut().unwrap();
+        match last_creation.retag.permission {
+            None => {
+                last_creation.retag.permission = Some(perm);
+            }
+            Some(previous) =>
+                if previous != perm {
+                    // 'Split up' the creation event.
+                    let previous_range = last_creation.retag.range;
+                    last_creation.retag.range = alloc_range(previous_range.start, self.offset);
+                    let mut new_event = last_creation.clone();
+                    new_event.retag.range = alloc_range(self.offset, previous_range.end());
+                    new_event.retag.permission = Some(perm);
+                    self.history.creations.push(new_event);
+                },
+        }
+    }
+
+    pub fn log_creation(&mut self) {
+        let Operation::Retag(op) = &self.operation else {
+            unreachable!("log_creation must only be called during a retag")
+        };
+        self.history
+            .creations
+            .push(Creation { retag: op.clone(), span: self.machine.current_span() });
+    }
+
+    pub fn log_invalidation(&mut self, tag: BorTag) {
+        let mut span = self.machine.current_span();
+        let (range, cause) = match &self.operation {
+            Operation::Retag(RetagOp { cause, range, permission, .. }) => {
+                if *cause == RetagCause::FnEntry {
+                    span = self.machine.caller_span();
+                }
+                (*range, InvalidationCause::Retag(permission.unwrap(), *cause))
+            }
+            Operation::Access(AccessOp { kind, range, .. }) =>
+                (*range, InvalidationCause::Access(*kind)),
+            Operation::Dealloc(_) => {
+                // This can be reached, but never be relevant later since the entire allocation is
+                // gone now.
+                return;
+            }
+        };
+        self.history.invalidations.push(Invalidation { tag, range, span, cause });
+    }
+
+    pub fn log_protector(&mut self) {
+        let Operation::Retag(op) = &self.operation else {
+            unreachable!("Protectors can only be created during a retag")
+        };
+        self.history
+            .protectors
+            .push(Protection { tag: op.new_tag, span: self.machine.current_span() });
+    }
+
+    pub fn get_logs_relevant_to(
+        &self,
+        tag: BorTag,
+        protector_tag: Option<BorTag>,
+    ) -> Option<TagHistory> {
+        let Some(created) = self.history
+            .creations
+            .iter()
+            .rev()
+            .find_map(|event| {
+                // First, look for a Creation event where the tag and the offset matches. This
+                // ensrues that we pick the right Creation event when a retag isn't uniform due to
+                // Freeze.
+                let range = event.retag.range;
+                if event.retag.new_tag == tag
+                    && self.offset >= range.start
+                    && self.offset < (range.start + range.size)
+                {
+                    Some(event.generate_diagnostic())
+                } else {
+                    None
+                }
+            })
+            .or_else(|| {
+                // If we didn't find anything with a matching offset, just return the event where
+                // the tag was created. This branch is hit when we use a tag at an offset that
+                // doesn't have the tag.
+                self.history.creations.iter().rev().find_map(|event| {
+                    if event.retag.new_tag == tag {
+                        Some(event.generate_diagnostic())
+                    } else {
+                        None
+                    }
+                })
+            }).or_else(|| {
+                // If we didn't find a retag that created this tag, it might be the base tag of
+                // this allocation.
+                if self.history.base.0.tag() == tag {
+                    Some((
+                        format!("{tag:?} was created here, as the base tag for {:?}", self.history.id),
+                        self.history.base.1.data()
+                    ))
+                } else {
+                    None
+                }
+            }) else {
+                // But if we don't have a creation event, this is related to a wildcard, and there
+                // is really nothing we can do to help.
+                return None;
+            };
+
+        let invalidated = self.history.invalidations.iter().rev().find_map(|event| {
+            if event.tag == tag { Some(event.generate_diagnostic()) } else { None }
+        });
+
+        let protected = protector_tag
+            .and_then(|protector| {
+                self.history.protectors.iter().find(|protection| protection.tag == protector)
+            })
+            .map(|protection| {
+                let protected_tag = protection.tag;
+                (format!("{protected_tag:?} is this argument"), protection.span.data())
+            });
+
+        Some(TagHistory { created, invalidated, protected })
+    }
+
+    /// Report a descriptive error when `new` could not be granted from `derived_from`.
+    #[inline(never)] // This is only called on fatal code paths
+    pub(super) fn grant_error(&self, stack: &Stack) -> InterpError<'tcx> {
+        let Operation::Retag(op) = &self.operation else {
+            unreachable!("grant_error should only be called during a retag")
+        };
+        let perm =
+            op.permission.expect("`start_grant` must be called before calling `grant_error`");
+        let action = format!(
+            "trying to retag from {:?} for {:?} permission at {:?}[{:#x}]",
+            op.orig_tag,
+            perm,
+            self.history.id,
+            self.offset.bytes(),
+        );
+        err_sb_ub(
+            format!("{action}{}", error_cause(stack, op.orig_tag)),
+            Some(operation_summary(&op.cause.summary(), self.history.id, op.range)),
+            op.orig_tag.and_then(|orig_tag| self.get_logs_relevant_to(orig_tag, None)),
+        )
+    }
+
+    /// Report a descriptive error when `access` is not permitted based on `tag`.
+    #[inline(never)] // This is only called on fatal code paths
+    pub(super) fn access_error(&self, stack: &Stack) -> InterpError<'tcx> {
+        // Deallocation and retagging also do an access as part of their thing, so handle that here, too.
+        let op = match &self.operation {
+            Operation::Access(op) => op,
+            Operation::Retag(_) => return self.grant_error(stack),
+            Operation::Dealloc(_) => return self.dealloc_error(stack),
+        };
+        let action = format!(
+            "attempting a {access} using {tag:?} at {alloc_id:?}[{offset:#x}]",
+            access = op.kind,
+            tag = op.tag,
+            alloc_id = self.history.id,
+            offset = self.offset.bytes(),
+        );
+        err_sb_ub(
+            format!("{action}{}", error_cause(stack, op.tag)),
+            Some(operation_summary("an access", self.history.id, op.range)),
+            op.tag.and_then(|tag| self.get_logs_relevant_to(tag, None)),
+        )
+    }
+
+    #[inline(never)] // This is only called on fatal code paths
+    pub(super) fn protector_error(&self, item: &Item, kind: ProtectorKind) -> InterpError<'tcx> {
+        let protected = match kind {
+            ProtectorKind::WeakProtector => "weakly protected",
+            ProtectorKind::StrongProtector => "strongly protected",
+        };
+        let call_id = self
+            .machine
+            .threads
+            .all_stacks()
+            .flatten()
+            .map(|frame| {
+                frame.extra.borrow_tracker.as_ref().expect("we should have borrow tracking data")
+            })
+            .find(|frame| frame.protected_tags.contains(&item.tag()))
+            .map(|frame| frame.call_id)
+            .unwrap(); // FIXME: Surely we should find something, but a panic seems wrong here?
+        match self.operation {
+            Operation::Dealloc(_) =>
+                err_sb_ub(
+                    format!("deallocating while item {item:?} is {protected} by call {call_id:?}",),
+                    None,
+                    None,
+                ),
+            Operation::Retag(RetagOp { orig_tag: tag, .. })
+            | Operation::Access(AccessOp { tag, .. }) =>
+                err_sb_ub(
+                    format!(
+                        "not granting access to tag {tag:?} because that would remove {item:?} which is {protected} because it is an argument of call {call_id:?}",
+                    ),
+                    None,
+                    tag.and_then(|tag| self.get_logs_relevant_to(tag, Some(item.tag()))),
+                ),
+        }
+    }
+
+    #[inline(never)] // This is only called on fatal code paths
+    pub fn dealloc_error(&self, stack: &Stack) -> InterpError<'tcx> {
+        let Operation::Dealloc(op) = &self.operation else {
+            unreachable!("dealloc_error should only be called during a deallocation")
+        };
+        err_sb_ub(
+            format!(
+                "attempting deallocation using {tag:?} at {alloc_id:?}{cause}",
+                tag = op.tag,
+                alloc_id = self.history.id,
+                cause = error_cause(stack, op.tag),
+            ),
+            None,
+            op.tag.and_then(|tag| self.get_logs_relevant_to(tag, None)),
+        )
+    }
+
+    #[inline(never)]
+    pub fn check_tracked_tag_popped(&self, item: &Item, global: &GlobalStateInner) {
+        if !global.tracked_pointer_tags.contains(&item.tag()) {
+            return;
+        }
+        let cause = match self.operation {
+            Operation::Dealloc(_) => format!(" due to deallocation"),
+            Operation::Access(AccessOp { kind, tag, .. }) =>
+                format!(" due to {kind:?} access for {tag:?}"),
+            Operation::Retag(RetagOp { orig_tag, permission, new_tag, .. }) => {
+                let permission = permission
+                    .expect("start_grant should set the current permission before popping a tag");
+                format!(" due to {permission:?} retag from {orig_tag:?} (that retag created {new_tag:?})")
+            }
+        };
+
+        self.machine.emit_diagnostic(NonHaltingDiagnostic::PoppedPointerTag(*item, cause));
+    }
+}
+
+fn operation_summary(operation: &str, alloc_id: AllocId, alloc_range: AllocRange) -> String {
+    format!("this error occurs as part of {operation} at {alloc_id:?}{alloc_range:?}")
+}
+
+fn error_cause(stack: &Stack, prov_extra: ProvenanceExtra) -> &'static str {
+    if let ProvenanceExtra::Concrete(tag) = prov_extra {
+        if (0..stack.len())
+            .map(|i| stack.get(i).unwrap())
+            .any(|item| item.tag() == tag && item.perm() != Permission::Disabled)
+        {
+            ", but that tag only grants SharedReadOnly permission for this location"
+        } else {
+            ", but that tag does not exist in the borrow stack for this location"
+        }
+    } else {
+        ", but no exposed tags have suitable permission in the borrow stack for this location"
+    }
+}
+
+impl RetagCause {
+    fn summary(&self) -> String {
+        match self {
+            RetagCause::Normal => "retag",
+            RetagCause::FnEntry => "FnEntry retag",
+            RetagCause::FnReturn => "FnReturn retag",
+            RetagCause::TwoPhase => "two-phase retag",
+        }
+        .to_string()
+    }
+}
diff --git a/src/tools/miri/src/borrow_tracker/stacked_borrows/item.rs b/src/tools/miri/src/borrow_tracker/stacked_borrows/item.rs
new file mode 100644 (file)
index 0000000..b9a52e4
--- /dev/null
@@ -0,0 +1,104 @@
+use std::fmt;
+
+use crate::borrow_tracker::BorTag;
+
+/// An item in the per-location borrow stack.
+#[derive(Copy, Clone, Hash, PartialEq, Eq)]
+pub struct Item(u64);
+
+// An Item contains 3 bitfields:
+// * Bits 0-61 store a BorTag
+// * Bits 61-63 store a Permission
+// * Bit 64 stores a flag which indicates if we have a protector
+const TAG_MASK: u64 = u64::MAX >> 3;
+const PERM_MASK: u64 = 0x3 << 61;
+const PROTECTED_MASK: u64 = 0x1 << 63;
+
+const PERM_SHIFT: u64 = 61;
+const PROTECTED_SHIFT: u64 = 63;
+
+impl Item {
+    pub fn new(tag: BorTag, perm: Permission, protected: bool) -> Self {
+        assert!(tag.get() <= TAG_MASK);
+        let packed_tag = tag.get();
+        let packed_perm = perm.to_bits() << PERM_SHIFT;
+        let packed_protected = u64::from(protected) << PROTECTED_SHIFT;
+
+        let new = Self(packed_tag | packed_perm | packed_protected);
+
+        debug_assert!(new.tag() == tag);
+        debug_assert!(new.perm() == perm);
+        debug_assert!(new.protected() == protected);
+
+        new
+    }
+
+    /// The pointers the permission is granted to.
+    pub fn tag(self) -> BorTag {
+        BorTag::new(self.0 & TAG_MASK).unwrap()
+    }
+
+    /// The permission this item grants.
+    pub fn perm(self) -> Permission {
+        Permission::from_bits((self.0 & PERM_MASK) >> PERM_SHIFT)
+    }
+
+    /// Whether or not there is a protector for this tag
+    pub fn protected(self) -> bool {
+        self.0 & PROTECTED_MASK > 0
+    }
+
+    /// Set the Permission stored in this Item
+    pub fn set_permission(&mut self, perm: Permission) {
+        // Clear the current set permission
+        self.0 &= !PERM_MASK;
+        // Write Permission::Disabled to the Permission bits
+        self.0 |= perm.to_bits() << PERM_SHIFT;
+    }
+}
+
+impl fmt::Debug for Item {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        write!(f, "[{:?} for {:?}]", self.perm(), self.tag())
+    }
+}
+
+/// Indicates which permission is granted (by this item to some pointers)
+#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
+pub enum Permission {
+    /// Grants unique mutable access.
+    Unique,
+    /// Grants shared mutable access.
+    SharedReadWrite,
+    /// Grants shared read-only access.
+    SharedReadOnly,
+    /// Grants no access, but separates two groups of SharedReadWrite so they are not
+    /// all considered mutually compatible.
+    Disabled,
+}
+
+impl Permission {
+    const UNIQUE: u64 = 0;
+    const SHARED_READ_WRITE: u64 = 1;
+    const SHARED_READ_ONLY: u64 = 2;
+    const DISABLED: u64 = 3;
+
+    fn to_bits(self) -> u64 {
+        match self {
+            Permission::Unique => Self::UNIQUE,
+            Permission::SharedReadWrite => Self::SHARED_READ_WRITE,
+            Permission::SharedReadOnly => Self::SHARED_READ_ONLY,
+            Permission::Disabled => Self::DISABLED,
+        }
+    }
+
+    fn from_bits(perm: u64) -> Self {
+        match perm {
+            Self::UNIQUE => Permission::Unique,
+            Self::SHARED_READ_WRITE => Permission::SharedReadWrite,
+            Self::SHARED_READ_ONLY => Permission::SharedReadOnly,
+            Self::DISABLED => Permission::Disabled,
+            _ => unreachable!(),
+        }
+    }
+}
diff --git a/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs b/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs
new file mode 100644 (file)
index 0000000..ffbc008
--- /dev/null
@@ -0,0 +1,1049 @@
+//! Implements "Stacked Borrows".  See <https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md>
+//! for further information.
+
+pub mod diagnostics;
+mod item;
+mod stack;
+
+use log::trace;
+use std::cmp;
+use std::fmt::Write;
+
+use rustc_data_structures::fx::FxHashSet;
+use rustc_middle::mir::{Mutability, RetagKind};
+use rustc_middle::ty::{
+    self,
+    layout::{HasParamEnv, LayoutOf},
+};
+use rustc_target::abi::{Abi, Size};
+
+use crate::borrow_tracker::{
+    stacked_borrows::diagnostics::{AllocHistory, DiagnosticCx, DiagnosticCxBuilder, TagHistory},
+    AccessKind, GlobalStateInner, ProtectorKind, RetagFields,
+};
+use crate::*;
+
+use diagnostics::RetagCause;
+pub use item::{Item, Permission};
+pub use stack::Stack;
+
+pub type AllocState = Stacks;
+
+/// Extra per-allocation state.
+#[derive(Clone, Debug)]
+pub struct Stacks {
+    // Even reading memory can have effects on the stack, so we need a `RefCell` here.
+    stacks: RangeMap<Stack>,
+    /// Stores past operations on this allocation
+    history: AllocHistory,
+    /// The set of tags that have been exposed inside this allocation.
+    exposed_tags: FxHashSet<BorTag>,
+    /// Whether this memory has been modified since the last time the tag GC ran
+    modified_since_last_gc: bool,
+}
+
+/// Indicates which permissions to grant to the retagged pointer.
+#[derive(Clone, Debug)]
+enum NewPermission {
+    Uniform {
+        perm: Permission,
+        access: Option<AccessKind>,
+        protector: Option<ProtectorKind>,
+    },
+    FreezeSensitive {
+        freeze_perm: Permission,
+        freeze_access: Option<AccessKind>,
+        freeze_protector: Option<ProtectorKind>,
+        nonfreeze_perm: Permission,
+        nonfreeze_access: Option<AccessKind>,
+        // nonfreeze_protector must always be None
+    },
+}
+
+impl NewPermission {
+    /// A key function: determine the permissions to grant at a retag for the given kind of
+    /// reference/pointer.
+    fn from_ref_ty<'tcx>(
+        ty: ty::Ty<'tcx>,
+        kind: RetagKind,
+        cx: &crate::MiriInterpCx<'_, 'tcx>,
+    ) -> Self {
+        let protector = (kind == RetagKind::FnEntry).then_some(ProtectorKind::StrongProtector);
+        match ty.kind() {
+            ty::Ref(_, pointee, Mutability::Mut) => {
+                if kind == RetagKind::TwoPhase {
+                    // We mostly just give up on 2phase-borrows, and treat these exactly like raw pointers.
+                    assert!(protector.is_none()); // RetagKind can't be both FnEntry and TwoPhase.
+                    NewPermission::Uniform {
+                        perm: Permission::SharedReadWrite,
+                        access: None,
+                        protector: None,
+                    }
+                } else if pointee.is_unpin(*cx.tcx, cx.param_env()) {
+                    // A regular full mutable reference.
+                    NewPermission::Uniform {
+                        perm: Permission::Unique,
+                        access: Some(AccessKind::Write),
+                        protector,
+                    }
+                } else {
+                    NewPermission::Uniform {
+                        perm: Permission::SharedReadWrite,
+                        // FIXME: We emit `dereferenceable` for `!Unpin` mutable references, so we
+                        // should do fake accesses here. But then we run into
+                        // <https://github.com/rust-lang/unsafe-code-guidelines/issues/381>, so for now
+                        // we don't do that.
+                        access: None,
+                        protector,
+                    }
+                }
+            }
+            ty::RawPtr(ty::TypeAndMut { mutbl: Mutability::Mut, .. }) => {
+                assert!(protector.is_none()); // RetagKind can't be both FnEntry and Raw.
+                // Mutable raw pointer. No access, not protected.
+                NewPermission::Uniform {
+                    perm: Permission::SharedReadWrite,
+                    access: None,
+                    protector: None,
+                }
+            }
+            ty::Ref(_, _pointee, Mutability::Not) => {
+                NewPermission::FreezeSensitive {
+                    freeze_perm: Permission::SharedReadOnly,
+                    freeze_access: Some(AccessKind::Read),
+                    freeze_protector: protector,
+                    nonfreeze_perm: Permission::SharedReadWrite,
+                    // Inside UnsafeCell, this does *not* count as an access, as there
+                    // might actually be mutable references further up the stack that
+                    // we have to keep alive.
+                    nonfreeze_access: None,
+                    // We do not protect inside UnsafeCell.
+                    // This fixes https://github.com/rust-lang/rust/issues/55005.
+                }
+            }
+            ty::RawPtr(ty::TypeAndMut { mutbl: Mutability::Not, .. }) => {
+                assert!(protector.is_none()); // RetagKind can't be both FnEntry and Raw.
+                // `*const T`, when freshly created, are read-only in the frozen part.
+                NewPermission::FreezeSensitive {
+                    freeze_perm: Permission::SharedReadOnly,
+                    freeze_access: Some(AccessKind::Read),
+                    freeze_protector: None,
+                    nonfreeze_perm: Permission::SharedReadWrite,
+                    nonfreeze_access: None,
+                }
+            }
+            _ => unreachable!(),
+        }
+    }
+
+    fn protector(&self) -> Option<ProtectorKind> {
+        match self {
+            NewPermission::Uniform { protector, .. } => *protector,
+            NewPermission::FreezeSensitive { freeze_protector, .. } => *freeze_protector,
+        }
+    }
+}
+
+/// Error reporting
+pub fn err_sb_ub<'tcx>(
+    msg: String,
+    help: Option<String>,
+    history: Option<TagHistory>,
+) -> InterpError<'tcx> {
+    err_machine_stop!(TerminationInfo::StackedBorrowsUb { msg, help, history })
+}
+
+// # Stacked Borrows Core Begin
+
+/// We need to make at least the following things true:
+///
+/// U1: After creating a `Uniq`, it is at the top.
+/// U2: If the top is `Uniq`, accesses must be through that `Uniq` or remove it.
+/// U3: If an access happens with a `Uniq`, it requires the `Uniq` to be in the stack.
+///
+/// F1: After creating a `&`, the parts outside `UnsafeCell` have our `SharedReadOnly` on top.
+/// F2: If a write access happens, it pops the `SharedReadOnly`.  This has three pieces:
+///     F2a: If a write happens granted by an item below our `SharedReadOnly`, the `SharedReadOnly`
+///          gets popped.
+///     F2b: No `SharedReadWrite` or `Unique` will ever be added on top of our `SharedReadOnly`.
+/// F3: If an access happens with an `&` outside `UnsafeCell`,
+///     it requires the `SharedReadOnly` to still be in the stack.
+
+/// Core relation on `Permission` to define which accesses are allowed
+impl Permission {
+    /// This defines for a given permission, whether it permits the given kind of access.
+    fn grants(self, access: AccessKind) -> bool {
+        // Disabled grants nothing. Otherwise, all items grant read access, and except for SharedReadOnly they grant write access.
+        self != Permission::Disabled
+            && (access == AccessKind::Read || self != Permission::SharedReadOnly)
+    }
+}
+
+/// Determines whether an item was invalidated by a conflicting access, or by deallocation.
+#[derive(Copy, Clone, Debug)]
+enum ItemInvalidationCause {
+    Conflict,
+    Dealloc,
+}
+
+/// Core per-location operations: access, dealloc, reborrow.
+impl<'tcx> Stack {
+    /// Find the first write-incompatible item above the given one --
+    /// i.e, find the height to which the stack will be truncated when writing to `granting`.
+    fn find_first_write_incompatible(&self, granting: usize) -> usize {
+        let perm = self.get(granting).unwrap().perm();
+        match perm {
+            Permission::SharedReadOnly => bug!("Cannot use SharedReadOnly for writing"),
+            Permission::Disabled => bug!("Cannot use Disabled for anything"),
+            Permission::Unique => {
+                // On a write, everything above us is incompatible.
+                granting + 1
+            }
+            Permission::SharedReadWrite => {
+                // The SharedReadWrite *just* above us are compatible, to skip those.
+                let mut idx = granting + 1;
+                while let Some(item) = self.get(idx) {
+                    if item.perm() == Permission::SharedReadWrite {
+                        // Go on.
+                        idx += 1;
+                    } else {
+                        // Found first incompatible!
+                        break;
+                    }
+                }
+                idx
+            }
+        }
+    }
+
+    /// The given item was invalidated -- check its protectors for whether that will cause UB.
+    fn item_invalidated(
+        item: &Item,
+        global: &GlobalStateInner,
+        dcx: &mut DiagnosticCx<'_, '_, '_, 'tcx>,
+        cause: ItemInvalidationCause,
+    ) -> InterpResult<'tcx> {
+        if !global.tracked_pointer_tags.is_empty() {
+            dcx.check_tracked_tag_popped(item, global);
+        }
+
+        if !item.protected() {
+            return Ok(());
+        }
+
+        // We store tags twice, once in global.protected_tags and once in each call frame.
+        // We do this because consulting a single global set in this function is faster
+        // than attempting to search all call frames in the program for the `FrameExtra`
+        // (if any) which is protecting the popped tag.
+        //
+        // This duplication trades off making `end_call` slower to make this function faster. This
+        // trade-off is profitable in practice for a combination of two reasons.
+        // 1. A single protected tag can (and does in some programs) protect thousands of `Item`s.
+        //    Therefore, adding overhead in function call/return is profitable even if it only
+        //    saves a little work in this function.
+        // 2. Most frames protect only one or two tags. So this duplicative global turns a search
+        //    which ends up about linear in the number of protected tags in the program into a
+        //    constant time check (and a slow linear, because the tags in the frames aren't contiguous).
+        if let Some(&protector_kind) = global.protected_tags.get(&item.tag()) {
+            // The only way this is okay is if the protector is weak and we are deallocating with
+            // the right pointer.
+            let allowed = matches!(cause, ItemInvalidationCause::Dealloc)
+                && matches!(protector_kind, ProtectorKind::WeakProtector);
+            if !allowed {
+                return Err(dcx.protector_error(item, protector_kind).into());
+            }
+        }
+        Ok(())
+    }
+
+    /// Test if a memory `access` using pointer tagged `tag` is granted.
+    /// If yes, return the index of the item that granted it.
+    /// `range` refers the entire operation, and `offset` refers to the specific offset into the
+    /// allocation that we are currently checking.
+    fn access(
+        &mut self,
+        access: AccessKind,
+        tag: ProvenanceExtra,
+        global: &GlobalStateInner,
+        dcx: &mut DiagnosticCx<'_, '_, '_, 'tcx>,
+        exposed_tags: &FxHashSet<BorTag>,
+    ) -> InterpResult<'tcx> {
+        // Two main steps: Find granting item, remove incompatible items above.
+
+        // Step 1: Find granting item.
+        let granting_idx =
+            self.find_granting(access, tag, exposed_tags).map_err(|()| dcx.access_error(self))?;
+
+        // Step 2: Remove incompatible items above them.  Make sure we do not remove protected
+        // items.  Behavior differs for reads and writes.
+        // In case of wildcards/unknown matches, we remove everything that is *definitely* gone.
+        if access == AccessKind::Write {
+            // Remove everything above the write-compatible items, like a proper stack. This makes sure read-only and unique
+            // pointers become invalid on write accesses (ensures F2a, and ensures U2 for write accesses).
+            let first_incompatible_idx = if let Some(granting_idx) = granting_idx {
+                // The granting_idx *might* be approximate, but any lower idx would remove more
+                // things. Even if this is a Unique and the lower idx is an SRW (which removes
+                // less), there is an SRW group boundary here so strictly more would get removed.
+                self.find_first_write_incompatible(granting_idx)
+            } else {
+                // We are writing to something in the unknown part.
+                // There is a SRW group boundary between the unknown and the known, so everything is incompatible.
+                0
+            };
+            self.pop_items_after(first_incompatible_idx, |item| {
+                Stack::item_invalidated(&item, global, dcx, ItemInvalidationCause::Conflict)?;
+                dcx.log_invalidation(item.tag());
+                Ok(())
+            })?;
+        } else {
+            // On a read, *disable* all `Unique` above the granting item.  This ensures U2 for read accesses.
+            // The reason this is not following the stack discipline (by removing the first Unique and
+            // everything on top of it) is that in `let raw = &mut *x as *mut _; let _val = *x;`, the second statement
+            // would pop the `Unique` from the reborrow of the first statement, and subsequently also pop the
+            // `SharedReadWrite` for `raw`.
+            // This pattern occurs a lot in the standard library: create a raw pointer, then also create a shared
+            // reference and use that.
+            // We *disable* instead of removing `Unique` to avoid "connecting" two neighbouring blocks of SRWs.
+            let first_incompatible_idx = if let Some(granting_idx) = granting_idx {
+                // The granting_idx *might* be approximate, but any lower idx would disable more things.
+                granting_idx + 1
+            } else {
+                // We are reading from something in the unknown part. That means *all* `Unique` we know about are dead now.
+                0
+            };
+            self.disable_uniques_starting_at(first_incompatible_idx, |item| {
+                Stack::item_invalidated(&item, global, dcx, ItemInvalidationCause::Conflict)?;
+                dcx.log_invalidation(item.tag());
+                Ok(())
+            })?;
+        }
+
+        // If this was an approximate action, we now collapse everything into an unknown.
+        if granting_idx.is_none() || matches!(tag, ProvenanceExtra::Wildcard) {
+            // Compute the upper bound of the items that remain.
+            // (This is why we did all the work above: to reduce the items we have to consider here.)
+            let mut max = BorTag::one();
+            for i in 0..self.len() {
+                let item = self.get(i).unwrap();
+                // Skip disabled items, they cannot be matched anyway.
+                if !matches!(item.perm(), Permission::Disabled) {
+                    // We are looking for a strict upper bound, so add 1 to this tag.
+                    max = cmp::max(item.tag().succ().unwrap(), max);
+                }
+            }
+            if let Some(unk) = self.unknown_bottom() {
+                max = cmp::max(unk, max);
+            }
+            // Use `max` as new strict upper bound for everything.
+            trace!(
+                "access: forgetting stack to upper bound {max} due to wildcard or unknown access",
+                max = max.get(),
+            );
+            self.set_unknown_bottom(max);
+        }
+
+        // Done.
+        Ok(())
+    }
+
+    /// Deallocate a location: Like a write access, but also there must be no
+    /// active protectors at all because we will remove all items.
+    fn dealloc(
+        &mut self,
+        tag: ProvenanceExtra,
+        global: &GlobalStateInner,
+        dcx: &mut DiagnosticCx<'_, '_, '_, 'tcx>,
+        exposed_tags: &FxHashSet<BorTag>,
+    ) -> InterpResult<'tcx> {
+        // Step 1: Make a write access.
+        // As part of this we do regular protector checking, i.e. even weakly protected items cause UB when popped.
+        self.access(AccessKind::Write, tag, global, dcx, exposed_tags)?;
+
+        // Step 2: Pretend we remove the remaining items, checking if any are strongly protected.
+        for idx in (0..self.len()).rev() {
+            let item = self.get(idx).unwrap();
+            Stack::item_invalidated(&item, global, dcx, ItemInvalidationCause::Dealloc)?;
+        }
+
+        Ok(())
+    }
+
+    /// Derive a new pointer from one with the given tag.
+    ///
+    /// `access` indicates which kind of memory access this retag itself should correspond to.
+    fn grant(
+        &mut self,
+        derived_from: ProvenanceExtra,
+        new: Item,
+        access: Option<AccessKind>,
+        global: &GlobalStateInner,
+        dcx: &mut DiagnosticCx<'_, '_, '_, 'tcx>,
+        exposed_tags: &FxHashSet<BorTag>,
+    ) -> InterpResult<'tcx> {
+        dcx.start_grant(new.perm());
+
+        // Compute where to put the new item.
+        // Either way, we ensure that we insert the new item in a way such that between
+        // `derived_from` and the new one, there are only items *compatible with* `derived_from`.
+        let new_idx = if let Some(access) = access {
+            // Simple case: We are just a regular memory access, and then push our thing on top,
+            // like a regular stack.
+            // This ensures F2b for `Unique`, by removing offending `SharedReadOnly`.
+            self.access(access, derived_from, global, dcx, exposed_tags)?;
+
+            // We insert "as far up as possible": We know only compatible items are remaining
+            // on top of `derived_from`, and we want the new item at the top so that we
+            // get the strongest possible guarantees.
+            // This ensures U1 and F1.
+            self.len()
+        } else {
+            // The tricky case: creating a new SRW permission without actually being an access.
+            assert!(new.perm() == Permission::SharedReadWrite);
+
+            // First we figure out which item grants our parent (`derived_from`) this kind of access.
+            // We use that to determine where to put the new item.
+            let granting_idx = self
+                .find_granting(AccessKind::Write, derived_from, exposed_tags)
+                .map_err(|()| dcx.grant_error(self))?;
+
+            let (Some(granting_idx), ProvenanceExtra::Concrete(_)) = (granting_idx, derived_from) else {
+                // The parent is a wildcard pointer or matched the unknown bottom.
+                // This is approximate. Nobody knows what happened, so forget everything.
+                // The new thing is SRW anyway, so we cannot push it "on top of the unkown part"
+                // (for all we know, it might join an SRW group inside the unknown).
+                trace!("reborrow: forgetting stack entirely due to SharedReadWrite reborrow from wildcard or unknown");
+                self.set_unknown_bottom(global.next_ptr_tag);
+                return Ok(());
+            };
+
+            // SharedReadWrite can coexist with "existing loans", meaning they don't act like a write
+            // access.  Instead of popping the stack, we insert the item at the place the stack would
+            // be popped to (i.e., we insert it above all the write-compatible items).
+            // This ensures F2b by adding the new item below any potentially existing `SharedReadOnly`.
+            self.find_first_write_incompatible(granting_idx)
+        };
+
+        // Put the new item there.
+        trace!("reborrow: adding item {:?}", new);
+        self.insert(new_idx, new);
+        Ok(())
+    }
+}
+// # Stacked Borrows Core End
+
+/// Integration with the BorTag garbage collector
+impl Stacks {
+    pub fn remove_unreachable_tags(&mut self, live_tags: &FxHashSet<BorTag>) {
+        if self.modified_since_last_gc {
+            for stack in self.stacks.iter_mut_all() {
+                if stack.len() > 64 {
+                    stack.retain(live_tags);
+                }
+            }
+            self.modified_since_last_gc = false;
+        }
+    }
+}
+
+impl VisitTags for Stacks {
+    fn visit_tags(&self, visit: &mut dyn FnMut(BorTag)) {
+        for tag in self.exposed_tags.iter().copied() {
+            visit(tag);
+        }
+    }
+}
+
+/// Map per-stack operations to higher-level per-location-range operations.
+impl<'tcx> Stacks {
+    /// Creates a new stack with an initial tag. For diagnostic purposes, we also need to know
+    /// the [`AllocId`] of the allocation this is associated with.
+    fn new(
+        size: Size,
+        perm: Permission,
+        tag: BorTag,
+        id: AllocId,
+        machine: &MiriMachine<'_, '_>,
+    ) -> Self {
+        let item = Item::new(tag, perm, false);
+        let stack = Stack::new(item);
+
+        Stacks {
+            stacks: RangeMap::new(size, stack),
+            history: AllocHistory::new(id, item, machine),
+            exposed_tags: FxHashSet::default(),
+            modified_since_last_gc: false,
+        }
+    }
+
+    /// Call `f` on every stack in the range.
+    fn for_each(
+        &mut self,
+        range: AllocRange,
+        mut dcx_builder: DiagnosticCxBuilder<'_, '_, 'tcx>,
+        mut f: impl FnMut(
+            &mut Stack,
+            &mut DiagnosticCx<'_, '_, '_, 'tcx>,
+            &mut FxHashSet<BorTag>,
+        ) -> InterpResult<'tcx>,
+    ) -> InterpResult<'tcx> {
+        self.modified_since_last_gc = true;
+        for (offset, stack) in self.stacks.iter_mut(range.start, range.size) {
+            let mut dcx = dcx_builder.build(&mut self.history, offset);
+            f(stack, &mut dcx, &mut self.exposed_tags)?;
+            dcx_builder = dcx.unbuild();
+        }
+        Ok(())
+    }
+}
+
+/// Glue code to connect with Miri Machine Hooks
+impl Stacks {
+    pub fn new_allocation(
+        id: AllocId,
+        size: Size,
+        state: &mut GlobalStateInner,
+        kind: MemoryKind<MiriMemoryKind>,
+        machine: &MiriMachine<'_, '_>,
+    ) -> Self {
+        let (base_tag, perm) = match kind {
+            // New unique borrow. This tag is not accessible by the program,
+            // so it will only ever be used when using the local directly (i.e.,
+            // not through a pointer). That is, whenever we directly write to a local, this will pop
+            // everything else off the stack, invalidating all previous pointers,
+            // and in particular, *all* raw pointers.
+            MemoryKind::Stack => (state.base_ptr_tag(id, machine), Permission::Unique),
+            // Everything else is shared by default.
+            _ => (state.base_ptr_tag(id, machine), Permission::SharedReadWrite),
+        };
+        Stacks::new(size, perm, base_tag, id, machine)
+    }
+
+    #[inline(always)]
+    pub fn before_memory_read<'tcx, 'mir, 'ecx>(
+        &mut self,
+        alloc_id: AllocId,
+        tag: ProvenanceExtra,
+        range: AllocRange,
+        machine: &'ecx MiriMachine<'mir, 'tcx>,
+    ) -> InterpResult<'tcx>
+    where
+        'tcx: 'ecx,
+    {
+        trace!(
+            "read access with tag {:?}: {:?}, size {}",
+            tag,
+            Pointer::new(alloc_id, range.start),
+            range.size.bytes()
+        );
+        let dcx = DiagnosticCxBuilder::read(machine, tag, range);
+        let state = machine.borrow_tracker.as_ref().unwrap().borrow();
+        self.for_each(range, dcx, |stack, dcx, exposed_tags| {
+            stack.access(AccessKind::Read, tag, &state, dcx, exposed_tags)
+        })
+    }
+
+    #[inline(always)]
+    pub fn before_memory_write<'tcx>(
+        &mut self,
+        alloc_id: AllocId,
+        tag: ProvenanceExtra,
+        range: AllocRange,
+        machine: &mut MiriMachine<'_, 'tcx>,
+    ) -> InterpResult<'tcx> {
+        trace!(
+            "write access with tag {:?}: {:?}, size {}",
+            tag,
+            Pointer::new(alloc_id, range.start),
+            range.size.bytes()
+        );
+        let dcx = DiagnosticCxBuilder::write(machine, tag, range);
+        let state = machine.borrow_tracker.as_ref().unwrap().borrow();
+        self.for_each(range, dcx, |stack, dcx, exposed_tags| {
+            stack.access(AccessKind::Write, tag, &state, dcx, exposed_tags)
+        })
+    }
+
+    #[inline(always)]
+    pub fn before_memory_deallocation<'tcx>(
+        &mut self,
+        alloc_id: AllocId,
+        tag: ProvenanceExtra,
+        range: AllocRange,
+        machine: &mut MiriMachine<'_, 'tcx>,
+    ) -> InterpResult<'tcx> {
+        trace!("deallocation with tag {:?}: {:?}, size {}", tag, alloc_id, range.size.bytes());
+        let dcx = DiagnosticCxBuilder::dealloc(machine, tag);
+        let state = machine.borrow_tracker.as_ref().unwrap().borrow();
+        self.for_each(range, dcx, |stack, dcx, exposed_tags| {
+            stack.dealloc(tag, &state, dcx, exposed_tags)
+        })?;
+        Ok(())
+    }
+}
+
+/// Retagging/reborrowing.  There is some policy in here, such as which permissions
+/// to grant for which references, and when to add protectors.
+impl<'mir: 'ecx, 'tcx: 'mir, 'ecx> EvalContextPrivExt<'mir, 'tcx, 'ecx>
+    for crate::MiriInterpCx<'mir, 'tcx>
+{
+}
+trait EvalContextPrivExt<'mir: 'ecx, 'tcx: 'mir, 'ecx>: crate::MiriInterpCxExt<'mir, 'tcx> {
+    /// Returns the `AllocId` the reborrow was done in, if some actual borrow stack manipulation
+    /// happened.
+    fn sb_reborrow(
+        &mut self,
+        place: &MPlaceTy<'tcx, Provenance>,
+        size: Size,
+        new_perm: NewPermission,
+        new_tag: BorTag,
+        retag_cause: RetagCause, // What caused this retag, for diagnostics only
+    ) -> InterpResult<'tcx, Option<AllocId>> {
+        let this = self.eval_context_mut();
+
+        // It is crucial that this gets called on all code paths, to ensure we track tag creation.
+        let log_creation = |this: &MiriInterpCx<'mir, 'tcx>,
+                            loc: Option<(AllocId, Size, ProvenanceExtra)>| // alloc_id, base_offset, orig_tag
+         -> InterpResult<'tcx> {
+            let global = this.machine.borrow_tracker.as_ref().unwrap().borrow();
+            let ty = place.layout.ty;
+            if global.tracked_pointer_tags.contains(&new_tag) {
+                let mut kind_str = String::new();
+                match new_perm {
+                    NewPermission::Uniform { perm, .. } =>
+                        write!(kind_str, "{perm:?} permission").unwrap(),
+                    NewPermission::FreezeSensitive { freeze_perm, .. } if ty.is_freeze(*this.tcx, this.param_env()) =>
+                        write!(kind_str, "{freeze_perm:?} permission").unwrap(),
+                    NewPermission::FreezeSensitive { freeze_perm, nonfreeze_perm, .. }  =>
+                        write!(kind_str, "{freeze_perm:?}/{nonfreeze_perm:?} permission for frozen/non-frozen parts").unwrap(),
+                }
+                write!(kind_str, " (pointee type {ty})").unwrap();
+                this.emit_diagnostic(NonHaltingDiagnostic::CreatedPointerTag(
+                    new_tag.inner(),
+                    Some(kind_str),
+                    loc.map(|(alloc_id, base_offset, orig_tag)| (alloc_id, alloc_range(base_offset, size), orig_tag)),
+                ));
+            }
+            drop(global); // don't hold that reference any longer than we have to
+
+            let Some((alloc_id, base_offset, orig_tag)) = loc else {
+                return Ok(())
+            };
+
+            let (_size, _align, alloc_kind) = this.get_alloc_info(alloc_id);
+            match alloc_kind {
+                AllocKind::LiveData => {
+                    // This should have alloc_extra data, but `get_alloc_extra` can still fail
+                    // if converting this alloc_id from a global to a local one
+                    // uncovers a non-supported `extern static`.
+                    let extra = this.get_alloc_extra(alloc_id)?;
+                    let mut stacked_borrows = extra
+                        .borrow_tracker_sb()
+                        .borrow_mut();
+                    // Note that we create a *second* `DiagnosticCxBuilder` below for the actual retag.
+                    // FIXME: can this be done cleaner?
+                    let dcx = DiagnosticCxBuilder::retag(
+                        &this.machine,
+                        retag_cause,
+                        new_tag,
+                        orig_tag,
+                        alloc_range(base_offset, size),
+                    );
+                    let mut dcx = dcx.build(&mut stacked_borrows.history, base_offset);
+                    dcx.log_creation();
+                    if new_perm.protector().is_some() {
+                        dcx.log_protector();
+                    }
+                },
+                AllocKind::Function | AllocKind::VTable | AllocKind::Dead => {
+                    // No stacked borrows on these allocations.
+                }
+            }
+            Ok(())
+        };
+
+        if size == Size::ZERO {
+            trace!(
+                "reborrow of size 0: reference {:?} derived from {:?} (pointee {})",
+                new_tag,
+                place.ptr,
+                place.layout.ty,
+            );
+            // Don't update any stacks for a zero-sized access; borrow stacks are per-byte and this
+            // touches no bytes so there is no stack to put this tag in.
+            // However, if the pointer for this operation points at a real allocation we still
+            // record where it was created so that we can issue a helpful diagnostic if there is an
+            // attempt to use it for a non-zero-sized access.
+            // Dangling slices are a common case here; it's valid to get their length but with raw
+            // pointer tagging for example all calls to get_unchecked on them are invalid.
+            if let Ok((alloc_id, base_offset, orig_tag)) = this.ptr_try_get_alloc_id(place.ptr) {
+                log_creation(this, Some((alloc_id, base_offset, orig_tag)))?;
+                return Ok(Some(alloc_id));
+            }
+            // This pointer doesn't come with an AllocId. :shrug:
+            log_creation(this, None)?;
+            return Ok(None);
+        }
+
+        let (alloc_id, base_offset, orig_tag) = this.ptr_get_alloc_id(place.ptr)?;
+        log_creation(this, Some((alloc_id, base_offset, orig_tag)))?;
+
+        // Ensure we bail out if the pointer goes out-of-bounds (see miri#1050).
+        let (alloc_size, _) = this.get_live_alloc_size_and_align(alloc_id)?;
+        if base_offset + size > alloc_size {
+            throw_ub!(PointerOutOfBounds {
+                alloc_id,
+                alloc_size,
+                ptr_offset: this.machine_usize_to_isize(base_offset.bytes()),
+                ptr_size: size,
+                msg: CheckInAllocMsg::InboundsTest
+            });
+        }
+
+        trace!(
+            "reborrow: reference {:?} derived from {:?} (pointee {}): {:?}, size {}",
+            new_tag,
+            orig_tag,
+            place.layout.ty,
+            Pointer::new(alloc_id, base_offset),
+            size.bytes()
+        );
+
+        if let Some(protect) = new_perm.protector() {
+            // See comment in `Stack::item_invalidated` for why we store the tag twice.
+            this.frame_mut().extra.borrow_tracker.as_mut().unwrap().protected_tags.push(new_tag);
+            this.machine
+                .borrow_tracker
+                .as_mut()
+                .unwrap()
+                .get_mut()
+                .protected_tags
+                .insert(new_tag, protect);
+        }
+
+        // Update the stacks, according to the new permission information we are given.
+        match new_perm {
+            NewPermission::Uniform { perm, access, protector } => {
+                assert!(perm != Permission::SharedReadOnly);
+                // Here we can avoid `borrow()` calls because we have mutable references.
+                // Note that this asserts that the allocation is mutable -- but since we are creating a
+                // mutable pointer, that seems reasonable.
+                let (alloc_extra, machine) = this.get_alloc_extra_mut(alloc_id)?;
+                let stacked_borrows = alloc_extra.borrow_tracker_sb_mut().get_mut();
+                let item = Item::new(new_tag, perm, protector.is_some());
+                let range = alloc_range(base_offset, size);
+                let global = machine.borrow_tracker.as_ref().unwrap().borrow();
+                let dcx = DiagnosticCxBuilder::retag(
+                    machine,
+                    retag_cause,
+                    new_tag,
+                    orig_tag,
+                    alloc_range(base_offset, size),
+                );
+                stacked_borrows.for_each(range, dcx, |stack, dcx, exposed_tags| {
+                    stack.grant(orig_tag, item, access, &global, dcx, exposed_tags)
+                })?;
+                drop(global);
+                if let Some(access) = access {
+                    assert_eq!(access, AccessKind::Write);
+                    // Make sure the data race model also knows about this.
+                    if let Some(data_race) = alloc_extra.data_race.as_mut() {
+                        data_race.write(alloc_id, range, machine)?;
+                    }
+                }
+            }
+            NewPermission::FreezeSensitive {
+                freeze_perm,
+                freeze_access,
+                freeze_protector,
+                nonfreeze_perm,
+                nonfreeze_access,
+            } => {
+                // The permission is not uniform across the entire range!
+                // We need a frozen-sensitive reborrow.
+                // We have to use shared references to alloc/memory_extra here since
+                // `visit_freeze_sensitive` needs to access the global state.
+                let alloc_extra = this.get_alloc_extra(alloc_id)?;
+                let mut stacked_borrows = alloc_extra.borrow_tracker_sb().borrow_mut();
+                this.visit_freeze_sensitive(place, size, |mut range, frozen| {
+                    // Adjust range.
+                    range.start += base_offset;
+                    // We are only ever `SharedReadOnly` inside the frozen bits.
+                    let (perm, access, protector) = if frozen {
+                        (freeze_perm, freeze_access, freeze_protector)
+                    } else {
+                        (nonfreeze_perm, nonfreeze_access, None)
+                    };
+                    let item = Item::new(new_tag, perm, protector.is_some());
+                    let global = this.machine.borrow_tracker.as_ref().unwrap().borrow();
+                    let dcx = DiagnosticCxBuilder::retag(
+                        &this.machine,
+                        retag_cause,
+                        new_tag,
+                        orig_tag,
+                        alloc_range(base_offset, size),
+                    );
+                    stacked_borrows.for_each(range, dcx, |stack, dcx, exposed_tags| {
+                        stack.grant(orig_tag, item, access, &global, dcx, exposed_tags)
+                    })?;
+                    drop(global);
+                    if let Some(access) = access {
+                        assert_eq!(access, AccessKind::Read);
+                        // Make sure the data race model also knows about this.
+                        if let Some(data_race) = alloc_extra.data_race.as_ref() {
+                            data_race.read(alloc_id, range, &this.machine)?;
+                        }
+                    }
+                    Ok(())
+                })?;
+            }
+        }
+
+        Ok(Some(alloc_id))
+    }
+
+    /// Retags an indidual pointer, returning the retagged version.
+    /// `kind` indicates what kind of reference is being created.
+    fn sb_retag_reference(
+        &mut self,
+        val: &ImmTy<'tcx, Provenance>,
+        new_perm: NewPermission,
+        cause: RetagCause, // What caused this retag, for diagnostics only
+    ) -> InterpResult<'tcx, ImmTy<'tcx, Provenance>> {
+        let this = self.eval_context_mut();
+        // We want a place for where the ptr *points to*, so we get one.
+        let place = this.ref_to_mplace(val)?;
+        let size = this.size_and_align_of_mplace(&place)?.map(|(size, _)| size);
+        // FIXME: If we cannot determine the size (because the unsized tail is an `extern type`),
+        // bail out -- we cannot reasonably figure out which memory range to reborrow.
+        // See https://github.com/rust-lang/unsafe-code-guidelines/issues/276.
+        let size = match size {
+            Some(size) => size,
+            None => return Ok(val.clone()),
+        };
+
+        // Compute new borrow.
+        let new_tag = this.machine.borrow_tracker.as_mut().unwrap().get_mut().new_ptr();
+
+        // Reborrow.
+        let alloc_id = this.sb_reborrow(&place, size, new_perm, new_tag, cause)?;
+
+        // Adjust pointer.
+        let new_place = place.map_provenance(|p| {
+            p.map(|prov| {
+                match alloc_id {
+                    Some(alloc_id) => {
+                        // If `reborrow` could figure out the AllocId of this ptr, hard-code it into the new one.
+                        // Even if we started out with a wildcard, this newly retagged pointer is tied to that allocation.
+                        Provenance::Concrete { alloc_id, tag: new_tag }
+                    }
+                    None => {
+                        // Looks like this has to stay a wildcard pointer.
+                        assert!(matches!(prov, Provenance::Wildcard));
+                        Provenance::Wildcard
+                    }
+                }
+            })
+        });
+
+        // Return new pointer.
+        Ok(ImmTy::from_immediate(new_place.to_ref(this), val.layout))
+    }
+}
+
+impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriInterpCx<'mir, 'tcx> {}
+pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
+    fn sb_retag_ptr_value(
+        &mut self,
+        kind: RetagKind,
+        val: &ImmTy<'tcx, Provenance>,
+    ) -> InterpResult<'tcx, ImmTy<'tcx, Provenance>> {
+        let this = self.eval_context_mut();
+        let new_perm = NewPermission::from_ref_ty(val.layout.ty, kind, this);
+        let retag_cause = match kind {
+            RetagKind::TwoPhase { .. } => RetagCause::TwoPhase,
+            RetagKind::FnEntry => unreachable!(),
+            RetagKind::Raw | RetagKind::Default => RetagCause::Normal,
+        };
+        this.sb_retag_reference(&val, new_perm, retag_cause)
+    }
+
+    fn sb_retag_place_contents(
+        &mut self,
+        kind: RetagKind,
+        place: &PlaceTy<'tcx, Provenance>,
+    ) -> InterpResult<'tcx> {
+        let this = self.eval_context_mut();
+        let retag_fields = this.machine.borrow_tracker.as_mut().unwrap().get_mut().retag_fields;
+        let retag_cause = match kind {
+            RetagKind::Raw | RetagKind::TwoPhase { .. } => unreachable!(), // these can only happen in `retag_ptr_value`
+            RetagKind::FnEntry => RetagCause::FnEntry,
+            RetagKind::Default => RetagCause::Normal,
+        };
+        let mut visitor = RetagVisitor { ecx: this, kind, retag_cause, retag_fields };
+        return visitor.visit_value(place);
+
+        // The actual visitor.
+        struct RetagVisitor<'ecx, 'mir, 'tcx> {
+            ecx: &'ecx mut MiriInterpCx<'mir, 'tcx>,
+            kind: RetagKind,
+            retag_cause: RetagCause,
+            retag_fields: RetagFields,
+        }
+        impl<'ecx, 'mir, 'tcx> RetagVisitor<'ecx, 'mir, 'tcx> {
+            #[inline(always)] // yes this helps in our benchmarks
+            fn retag_ptr_inplace(
+                &mut self,
+                place: &PlaceTy<'tcx, Provenance>,
+                new_perm: NewPermission,
+                retag_cause: RetagCause,
+            ) -> InterpResult<'tcx> {
+                let val = self.ecx.read_immediate(&self.ecx.place_to_op(place)?)?;
+                let val = self.ecx.sb_retag_reference(&val, new_perm, retag_cause)?;
+                self.ecx.write_immediate(*val, place)?;
+                Ok(())
+            }
+        }
+        impl<'ecx, 'mir, 'tcx> MutValueVisitor<'mir, 'tcx, MiriMachine<'mir, 'tcx>>
+            for RetagVisitor<'ecx, 'mir, 'tcx>
+        {
+            type V = PlaceTy<'tcx, Provenance>;
+
+            #[inline(always)]
+            fn ecx(&mut self) -> &mut MiriInterpCx<'mir, 'tcx> {
+                self.ecx
+            }
+
+            fn visit_box(&mut self, place: &PlaceTy<'tcx, Provenance>) -> InterpResult<'tcx> {
+                // Boxes get a weak protectors, since they may be deallocated.
+                let new_perm = NewPermission::Uniform {
+                    perm: Permission::Unique,
+                    access: Some(AccessKind::Write),
+                    protector: (self.kind == RetagKind::FnEntry)
+                        .then_some(ProtectorKind::WeakProtector),
+                };
+                self.retag_ptr_inplace(place, new_perm, self.retag_cause)
+            }
+
+            fn visit_value(&mut self, place: &PlaceTy<'tcx, Provenance>) -> InterpResult<'tcx> {
+                // If this place is smaller than a pointer, we know that it can't contain any
+                // pointers we need to retag, so we can stop recursion early.
+                // This optimization is crucial for ZSTs, because they can contain way more fields
+                // than we can ever visit.
+                if place.layout.is_sized() && place.layout.size < self.ecx.pointer_size() {
+                    return Ok(());
+                }
+
+                // Check the type of this value to see what to do with it (retag, or recurse).
+                match place.layout.ty.kind() {
+                    ty::Ref(..) => {
+                        let new_perm =
+                            NewPermission::from_ref_ty(place.layout.ty, self.kind, self.ecx);
+                        self.retag_ptr_inplace(place, new_perm, self.retag_cause)?;
+                    }
+                    ty::RawPtr(..) => {
+                        // We do *not* want to recurse into raw pointers -- wide raw pointers have
+                        // fields, and for dyn Trait pointees those can have reference type!
+                    }
+                    ty::Adt(adt, _) if adt.is_box() => {
+                        // Recurse for boxes, they require some tricky handling and will end up in `visit_box` above.
+                        // (Yes this means we technically also recursively retag the allocator itself
+                        // even if field retagging is not enabled. *shrug*)
+                        self.walk_value(place)?;
+                    }
+                    _ => {
+                        // Not a reference/pointer/box. Only recurse if configured appropriately.
+                        let recurse = match self.retag_fields {
+                            RetagFields::No => false,
+                            RetagFields::Yes => true,
+                            RetagFields::OnlyScalar => {
+                                // Matching `ArgAbi::new` at the time of writing, only fields of
+                                // `Scalar` and `ScalarPair` ABI are considered.
+                                matches!(place.layout.abi, Abi::Scalar(..) | Abi::ScalarPair(..))
+                            }
+                        };
+                        if recurse {
+                            self.walk_value(place)?;
+                        }
+                    }
+                }
+
+                Ok(())
+            }
+        }
+    }
+
+    /// After a stack frame got pushed, retag the return place so that we are sure
+    /// it does not alias with anything.
+    ///
+    /// This is a HACK because there is nothing in MIR that would make the retag
+    /// explicit. Also see <https://github.com/rust-lang/rust/issues/71117>.
+    fn sb_retag_return_place(&mut self) -> InterpResult<'tcx> {
+        let this = self.eval_context_mut();
+        let return_place = &this.frame().return_place;
+        if return_place.layout.is_zst() {
+            // There may not be any memory here, nothing to do.
+            return Ok(());
+        }
+        // We need this to be in-memory to use tagged pointers.
+        let return_place = this.force_allocation(&return_place.clone())?;
+
+        // We have to turn the place into a pointer to use the existing code.
+        // (The pointer type does not matter, so we use a raw pointer.)
+        let ptr_layout = this.layout_of(this.tcx.mk_mut_ptr(return_place.layout.ty))?;
+        let val = ImmTy::from_immediate(return_place.to_ref(this), ptr_layout);
+        // Reborrow it. With protection! That is part of the point.
+        let new_perm = NewPermission::Uniform {
+            perm: Permission::Unique,
+            access: Some(AccessKind::Write),
+            protector: Some(ProtectorKind::StrongProtector),
+        };
+        let val = this.sb_retag_reference(&val, new_perm, RetagCause::FnReturn)?;
+        // And use reborrowed pointer for return place.
+        let return_place = this.ref_to_mplace(&val)?;
+        this.frame_mut().return_place = return_place.into();
+
+        Ok(())
+    }
+
+    /// Mark the given tag as exposed. It was found on a pointer with the given AllocId.
+    fn sb_expose_tag(&mut self, alloc_id: AllocId, tag: BorTag) -> InterpResult<'tcx> {
+        let this = self.eval_context_mut();
+
+        // Function pointers and dead objects don't have an alloc_extra so we ignore them.
+        // This is okay because accessing them is UB anyway, no need for any Stacked Borrows checks.
+        // NOT using `get_alloc_extra_mut` since this might be a read-only allocation!
+        let (_size, _align, kind) = this.get_alloc_info(alloc_id);
+        match kind {
+            AllocKind::LiveData => {
+                // This should have alloc_extra data, but `get_alloc_extra` can still fail
+                // if converting this alloc_id from a global to a local one
+                // uncovers a non-supported `extern static`.
+                let alloc_extra = this.get_alloc_extra(alloc_id)?;
+                trace!("Stacked Borrows tag {tag:?} exposed in {alloc_id:?}");
+                alloc_extra.borrow_tracker_sb().borrow_mut().exposed_tags.insert(tag);
+            }
+            AllocKind::Function | AllocKind::VTable | AllocKind::Dead => {
+                // No stacked borrows on these allocations.
+            }
+        }
+        Ok(())
+    }
+
+    fn print_stacks(&mut self, alloc_id: AllocId) -> InterpResult<'tcx> {
+        let this = self.eval_context_mut();
+        let alloc_extra = this.get_alloc_extra(alloc_id)?;
+        let stacks = alloc_extra.borrow_tracker_sb().borrow();
+        for (range, stack) in stacks.stacks.iter_all() {
+            print!("{range:?}: [");
+            if let Some(bottom) = stack.unknown_bottom() {
+                print!(" unknown-bottom(..{bottom:?})");
+            }
+            for i in 0..stack.len() {
+                let item = stack.get(i).unwrap();
+                print!(" {:?}{:?}", item.perm(), item.tag());
+            }
+            println!(" ]");
+        }
+        Ok(())
+    }
+}
diff --git a/src/tools/miri/src/borrow_tracker/stacked_borrows/stack.rs b/src/tools/miri/src/borrow_tracker/stacked_borrows/stack.rs
new file mode 100644 (file)
index 0000000..1d5cfec
--- /dev/null
@@ -0,0 +1,472 @@
+#[cfg(feature = "stack-cache")]
+use std::ops::Range;
+
+use rustc_data_structures::fx::FxHashSet;
+
+use crate::borrow_tracker::{
+    stacked_borrows::{Item, Permission},
+    AccessKind, BorTag,
+};
+use crate::ProvenanceExtra;
+
+/// Exactly what cache size we should use is a difficult tradeoff. There will always be some
+/// workload which has a `BorTag` working set which exceeds the size of the cache, and ends up
+/// falling back to linear searches of the borrow stack very often.
+/// The cost of making this value too large is that the loop in `Stack::insert` which ensures the
+/// entries in the cache stay correct after an insert becomes expensive.
+#[cfg(feature = "stack-cache")]
+const CACHE_LEN: usize = 32;
+
+/// Extra per-location state.
+#[derive(Clone, Debug)]
+pub struct Stack {
+    /// Used *mostly* as a stack; never empty.
+    /// Invariants:
+    /// * Above a `SharedReadOnly` there can only be more `SharedReadOnly`.
+    /// * Except for `Untagged`, no tag occurs in the stack more than once.
+    borrows: Vec<Item>,
+    /// If this is `Some(id)`, then the actual current stack is unknown. This can happen when
+    /// wildcard pointers are used to access this location. What we do know is that `borrows` are at
+    /// the top of the stack, and below it are arbitrarily many items whose `tag` is strictly less
+    /// than `id`.
+    /// When the bottom is unknown, `borrows` always has a `SharedReadOnly` or `Unique` at the bottom;
+    /// we never have the unknown-to-known boundary in an SRW group.
+    unknown_bottom: Option<BorTag>,
+
+    /// A small LRU cache of searches of the borrow stack.
+    #[cfg(feature = "stack-cache")]
+    cache: StackCache,
+    /// On a read, we need to disable all `Unique` above the granting item. We can avoid most of
+    /// this scan by keeping track of the region of the borrow stack that may contain `Unique`s.
+    #[cfg(feature = "stack-cache")]
+    unique_range: Range<usize>,
+}
+
+impl Stack {
+    pub fn retain(&mut self, tags: &FxHashSet<BorTag>) {
+        let mut first_removed = None;
+
+        // We never consider removing the bottom-most tag. For stacks without an unknown
+        // bottom this preserves the base tag.
+        // Note that the algorithm below is based on considering the tag at read_idx - 1,
+        // so precisely considering the tag at index 0 for removal when we have an unknown
+        // bottom would complicate the implementation. The simplification of not considering
+        // it does not have a significant impact on the degree to which the GC mititages
+        // memory growth.
+        let mut read_idx = 1;
+        let mut write_idx = read_idx;
+        while read_idx < self.borrows.len() {
+            let left = self.borrows[read_idx - 1];
+            let this = self.borrows[read_idx];
+            let should_keep = match this.perm() {
+                // SharedReadWrite is the simplest case, if it's unreachable we can just remove it.
+                Permission::SharedReadWrite => tags.contains(&this.tag()),
+                // Only retain a Disabled tag if it is terminating a SharedReadWrite block.
+                Permission::Disabled => left.perm() == Permission::SharedReadWrite,
+                // Unique and SharedReadOnly can terminate a SharedReadWrite block, so only remove
+                // them if they are both unreachable and not directly after a SharedReadWrite.
+                Permission::Unique | Permission::SharedReadOnly =>
+                    left.perm() == Permission::SharedReadWrite || tags.contains(&this.tag()),
+            };
+
+            if should_keep {
+                if read_idx != write_idx {
+                    self.borrows[write_idx] = self.borrows[read_idx];
+                }
+                write_idx += 1;
+            } else if first_removed.is_none() {
+                first_removed = Some(read_idx);
+            }
+
+            read_idx += 1;
+        }
+        self.borrows.truncate(write_idx);
+
+        #[cfg(not(feature = "stack-cache"))]
+        drop(first_removed); // This is only needed for the stack-cache
+
+        #[cfg(feature = "stack-cache")]
+        if let Some(first_removed) = first_removed {
+            // Either end of unique_range may have shifted, all we really know is that we can't
+            // have introduced a new Unique.
+            if !self.unique_range.is_empty() {
+                self.unique_range = 0..self.len();
+            }
+
+            // Replace any Items which have been collected with the base item, a known-good value.
+            for i in 0..CACHE_LEN {
+                if self.cache.idx[i] >= first_removed {
+                    self.cache.items[i] = self.borrows[0];
+                    self.cache.idx[i] = 0;
+                }
+            }
+        }
+    }
+}
+
+/// A very small cache of searches of a borrow stack, mapping `Item`s to their position in said stack.
+///
+/// It may seem like maintaining this cache is a waste for small stacks, but
+/// (a) iterating over small fixed-size arrays is super fast, and (b) empirically this helps *a lot*,
+/// probably because runtime is dominated by large stacks.
+#[cfg(feature = "stack-cache")]
+#[derive(Clone, Debug)]
+struct StackCache {
+    items: [Item; CACHE_LEN], // Hot in find_granting
+    idx: [usize; CACHE_LEN],  // Hot in grant
+}
+
+#[cfg(feature = "stack-cache")]
+impl StackCache {
+    /// When a tag is used, we call this function to add or refresh it in the cache.
+    ///
+    /// We use the position in the cache to represent how recently a tag was used; the first position
+    /// is the most recently used tag. So an add shifts every element towards the end, and inserts
+    /// the new element at the start. We lose the last element.
+    /// This strategy is effective at keeping the most-accessed items in the cache, but it costs a
+    /// linear shift across the entire cache when we add a new tag.
+    fn add(&mut self, idx: usize, item: Item) {
+        self.items.copy_within(0..CACHE_LEN - 1, 1);
+        self.items[0] = item;
+        self.idx.copy_within(0..CACHE_LEN - 1, 1);
+        self.idx[0] = idx;
+    }
+}
+
+impl PartialEq for Stack {
+    fn eq(&self, other: &Self) -> bool {
+        // All the semantics of Stack are in self.borrows, everything else is caching
+        self.borrows == other.borrows
+    }
+}
+
+impl Eq for Stack {}
+
+impl<'tcx> Stack {
+    /// Panics if any of the caching mechanisms have broken,
+    /// - The StackCache indices don't refer to the parallel items,
+    /// - There are no Unique items outside of first_unique..last_unique
+    #[cfg(all(feature = "stack-cache", debug_assertions))]
+    fn verify_cache_consistency(&self) {
+        // Only a full cache needs to be valid. Also see the comments in find_granting_cache
+        // and set_unknown_bottom.
+        if self.borrows.len() >= CACHE_LEN {
+            for (tag, stack_idx) in self.cache.items.iter().zip(self.cache.idx.iter()) {
+                assert_eq!(self.borrows[*stack_idx], *tag);
+            }
+        }
+
+        // Check that all Unique items fall within unique_range.
+        for (idx, item) in self.borrows.iter().enumerate() {
+            if item.perm() == Permission::Unique {
+                assert!(
+                    self.unique_range.contains(&idx),
+                    "{:?} {:?}",
+                    self.unique_range,
+                    self.borrows
+                );
+            }
+        }
+
+        // Check that the unique_range is a valid index into the borrow stack.
+        // This asserts that the unique_range's start <= end.
+        let _uniques = &self.borrows[self.unique_range.clone()];
+
+        // We cannot assert that the unique range is precise.
+        // Both ends may shift around when `Stack::retain` is called. Additionally,
+        // when we pop items within the unique range, setting the end of the range precisely
+        // requires doing a linear search of the borrow stack, which is exactly the kind of
+        // operation that all this caching exists to avoid.
+    }
+
+    /// Find the item granting the given kind of access to the given tag, and return where
+    /// it is on the stack. For wildcard tags, the given index is approximate, but if *no*
+    /// index is given it means the match was *not* in the known part of the stack.
+    /// `Ok(None)` indicates it matched the "unknown" part of the stack.
+    /// `Err` indicates it was not found.
+    pub(super) fn find_granting(
+        &mut self,
+        access: AccessKind,
+        tag: ProvenanceExtra,
+        exposed_tags: &FxHashSet<BorTag>,
+    ) -> Result<Option<usize>, ()> {
+        #[cfg(all(feature = "stack-cache", debug_assertions))]
+        self.verify_cache_consistency();
+
+        let ProvenanceExtra::Concrete(tag) = tag else {
+            // Handle the wildcard case.
+            // Go search the stack for an exposed tag.
+            if let Some(idx) =
+                self.borrows
+                    .iter()
+                    .enumerate() // we also need to know *where* in the stack
+                    .rev() // search top-to-bottom
+                    .find_map(|(idx, item)| {
+                        // If the item fits and *might* be this wildcard, use it.
+                        if item.perm().grants(access) && exposed_tags.contains(&item.tag()) {
+                            Some(idx)
+                        } else {
+                            None
+                        }
+                    })
+            {
+                return Ok(Some(idx));
+            }
+            // If we couldn't find it in the stack, check the unknown bottom.
+            return if self.unknown_bottom.is_some() { Ok(None) } else { Err(()) };
+        };
+
+        if let Some(idx) = self.find_granting_tagged(access, tag) {
+            return Ok(Some(idx));
+        }
+
+        // Couldn't find it in the stack; but if there is an unknown bottom it might be there.
+        let found = self.unknown_bottom.is_some_and(|unknown_limit| {
+            tag < unknown_limit // unknown_limit is an upper bound for what can be in the unknown bottom.
+        });
+        if found { Ok(None) } else { Err(()) }
+    }
+
+    fn find_granting_tagged(&mut self, access: AccessKind, tag: BorTag) -> Option<usize> {
+        #[cfg(feature = "stack-cache")]
+        if let Some(idx) = self.find_granting_cache(access, tag) {
+            return Some(idx);
+        }
+
+        // If we didn't find the tag in the cache, fall back to a linear search of the
+        // whole stack, and add the tag to the cache.
+        for (stack_idx, item) in self.borrows.iter().enumerate().rev() {
+            if tag == item.tag() && item.perm().grants(access) {
+                #[cfg(feature = "stack-cache")]
+                self.cache.add(stack_idx, *item);
+                return Some(stack_idx);
+            }
+        }
+        None
+    }
+
+    #[cfg(feature = "stack-cache")]
+    fn find_granting_cache(&mut self, access: AccessKind, tag: BorTag) -> Option<usize> {
+        // This looks like a common-sense optimization; we're going to do a linear search of the
+        // cache or the borrow stack to scan the shorter of the two. This optimization is miniscule
+        // and this check actually ensures we do not access an invalid cache.
+        // When a stack is created and when items are removed from the top of the borrow stack, we
+        // need some valid value to populate the cache. In both cases, we try to use the bottom
+        // item. But when the stack is cleared in `set_unknown_bottom` there is nothing we could
+        // place in the cache that is correct. But due to the way we populate the cache in
+        // `StackCache::add`, we know that when the borrow stack has grown larger than the cache,
+        // every slot in the cache is valid.
+        if self.borrows.len() <= CACHE_LEN {
+            return None;
+        }
+        // Search the cache for the tag we're looking up
+        let cache_idx = self.cache.items.iter().position(|t| t.tag() == tag)?;
+        let stack_idx = self.cache.idx[cache_idx];
+        // If we found the tag, look up its position in the stack to see if it grants
+        // the required permission
+        if self.cache.items[cache_idx].perm().grants(access) {
+            // If it does, and it's not already in the most-recently-used position, re-insert it at
+            // the most-recently-used position. This technically reduces the efficiency of the
+            // cache by duplicating elements, but current benchmarks do not seem to benefit from
+            // avoiding this duplication.
+            // But if the tag is in position 1, avoiding the duplicating add is trivial.
+            // If it does, and it's not already in the most-recently-used position, move it there.
+            // Except if the tag is in position 1, this is equivalent to just a swap, so do that.
+            if cache_idx == 1 {
+                self.cache.items.swap(0, 1);
+                self.cache.idx.swap(0, 1);
+            } else if cache_idx > 1 {
+                self.cache.add(stack_idx, self.cache.items[cache_idx]);
+            }
+            Some(stack_idx)
+        } else {
+            // Tag is in the cache, but it doesn't grant the required permission
+            None
+        }
+    }
+
+    pub fn insert(&mut self, new_idx: usize, new: Item) {
+        self.borrows.insert(new_idx, new);
+
+        #[cfg(feature = "stack-cache")]
+        self.insert_cache(new_idx, new);
+    }
+
+    #[cfg(feature = "stack-cache")]
+    fn insert_cache(&mut self, new_idx: usize, new: Item) {
+        // Adjust the possibly-unique range if an insert occurs before or within it
+        if self.unique_range.start >= new_idx {
+            self.unique_range.start += 1;
+        }
+        if self.unique_range.end >= new_idx {
+            self.unique_range.end += 1;
+        }
+        if new.perm() == Permission::Unique {
+            // If this is the only Unique, set the range to contain just the new item.
+            if self.unique_range.is_empty() {
+                self.unique_range = new_idx..new_idx + 1;
+            } else {
+                // We already have other Unique items, expand the range to include the new item
+                self.unique_range.start = self.unique_range.start.min(new_idx);
+                self.unique_range.end = self.unique_range.end.max(new_idx + 1);
+            }
+        }
+
+        // The above insert changes the meaning of every index in the cache >= new_idx, so now
+        // we need to find every one of those indexes and increment it.
+        // But if the insert is at the end (equivalent to a push), we can skip this step because
+        // it didn't change the position of any other items.
+        if new_idx != self.borrows.len() - 1 {
+            for idx in &mut self.cache.idx {
+                if *idx >= new_idx {
+                    *idx += 1;
+                }
+            }
+        }
+
+        // This primes the cache for the next access, which is almost always the just-added tag.
+        self.cache.add(new_idx, new);
+
+        #[cfg(debug_assertions)]
+        self.verify_cache_consistency();
+    }
+
+    /// Construct a new `Stack` using the passed `Item` as the base tag.
+    pub fn new(item: Item) -> Self {
+        Stack {
+            borrows: vec![item],
+            unknown_bottom: None,
+            #[cfg(feature = "stack-cache")]
+            cache: StackCache { idx: [0; CACHE_LEN], items: [item; CACHE_LEN] },
+            #[cfg(feature = "stack-cache")]
+            unique_range: if item.perm() == Permission::Unique { 0..1 } else { 0..0 },
+        }
+    }
+
+    pub fn get(&self, idx: usize) -> Option<Item> {
+        self.borrows.get(idx).cloned()
+    }
+
+    #[allow(clippy::len_without_is_empty)] // Stacks are never empty
+    pub fn len(&self) -> usize {
+        self.borrows.len()
+    }
+
+    pub fn unknown_bottom(&self) -> Option<BorTag> {
+        self.unknown_bottom
+    }
+
+    pub fn set_unknown_bottom(&mut self, tag: BorTag) {
+        // We clear the borrow stack but the lookup cache doesn't support clearing per se. Instead,
+        // there is a check explained in `find_granting_cache` which protects against accessing the
+        // cache when it has been cleared and not yet refilled.
+        self.borrows.clear();
+        self.unknown_bottom = Some(tag);
+        #[cfg(feature = "stack-cache")]
+        {
+            self.unique_range = 0..0;
+        }
+    }
+
+    /// Find all `Unique` elements in this borrow stack above `granting_idx`, pass a copy of them
+    /// to the `visitor`, then set their `Permission` to `Disabled`.
+    pub fn disable_uniques_starting_at(
+        &mut self,
+        disable_start: usize,
+        mut visitor: impl FnMut(Item) -> crate::InterpResult<'tcx>,
+    ) -> crate::InterpResult<'tcx> {
+        #[cfg(feature = "stack-cache")]
+        let unique_range = self.unique_range.clone();
+        #[cfg(not(feature = "stack-cache"))]
+        let unique_range = 0..self.len();
+
+        if disable_start <= unique_range.end {
+            let lower = unique_range.start.max(disable_start);
+            let upper = unique_range.end;
+            for item in &mut self.borrows[lower..upper] {
+                if item.perm() == Permission::Unique {
+                    log::trace!("access: disabling item {:?}", item);
+                    visitor(*item)?;
+                    item.set_permission(Permission::Disabled);
+                    // Also update all copies of this item in the cache.
+                    #[cfg(feature = "stack-cache")]
+                    for it in &mut self.cache.items {
+                        if it.tag() == item.tag() {
+                            it.set_permission(Permission::Disabled);
+                        }
+                    }
+                }
+            }
+        }
+
+        #[cfg(feature = "stack-cache")]
+        if disable_start <= self.unique_range.start {
+            // We disabled all Unique items
+            self.unique_range.start = 0;
+            self.unique_range.end = 0;
+        } else {
+            // Truncate the range to only include items up to the index that we started disabling
+            // at.
+            self.unique_range.end = self.unique_range.end.min(disable_start);
+        }
+
+        #[cfg(all(feature = "stack-cache", debug_assertions))]
+        self.verify_cache_consistency();
+
+        Ok(())
+    }
+
+    /// Produces an iterator which iterates over `range` in reverse, and when dropped removes that
+    /// range of `Item`s from this `Stack`.
+    pub fn pop_items_after<V: FnMut(Item) -> crate::InterpResult<'tcx>>(
+        &mut self,
+        start: usize,
+        mut visitor: V,
+    ) -> crate::InterpResult<'tcx> {
+        while self.borrows.len() > start {
+            let item = self.borrows.pop().unwrap();
+            visitor(item)?;
+        }
+
+        #[cfg(feature = "stack-cache")]
+        if !self.borrows.is_empty() {
+            // After we remove from the borrow stack, every aspect of our caching may be invalid, but it is
+            // also possible that the whole cache is still valid. So we call this method to repair what
+            // aspects of the cache are now invalid, instead of resetting the whole thing to a trivially
+            // valid default state.
+            let base_tag = self.borrows[0];
+            let mut removed = 0;
+            let mut cursor = 0;
+            // Remove invalid entries from the cache by rotating them to the end of the cache, then
+            // keep track of how many invalid elements there are and overwrite them with the base tag.
+            // The base tag here serves as a harmless default value.
+            for _ in 0..CACHE_LEN - 1 {
+                if self.cache.idx[cursor] >= start {
+                    self.cache.idx[cursor..CACHE_LEN - removed].rotate_left(1);
+                    self.cache.items[cursor..CACHE_LEN - removed].rotate_left(1);
+                    removed += 1;
+                } else {
+                    cursor += 1;
+                }
+            }
+            for i in CACHE_LEN - removed - 1..CACHE_LEN {
+                self.cache.idx[i] = 0;
+                self.cache.items[i] = base_tag;
+            }
+
+            if start <= self.unique_range.start {
+                // We removed all the Unique items
+                self.unique_range = 0..0;
+            } else {
+                // Ensure the range doesn't extend past the new top of the stack
+                self.unique_range.end = self.unique_range.end.min(start);
+            }
+        } else {
+            self.unique_range = 0..0;
+        }
+
+        #[cfg(all(feature = "stack-cache", debug_assertions))]
+        self.verify_cache_consistency();
+        Ok(())
+    }
+}
index cfbeb347cabb6ddd1a85af6899475869f7c190c2..bcbf45a3d24085fa01f97b9a9fd13dcf3f1c3380 100644 (file)
@@ -59,7 +59,7 @@
     weak_memory::EvalContextExt as _,
 };
 
-pub type AllocExtra = VClockAlloc;
+pub type AllocState = VClockAlloc;
 
 /// Valid atomic read-write orderings, alias of atomic::Ordering (not non-exhaustive).
 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
@@ -670,7 +670,7 @@ pub struct VClockAlloc {
 }
 
 impl VisitTags for VClockAlloc {
-    fn visit_tags(&self, _visit: &mut dyn FnMut(SbTag)) {
+    fn visit_tags(&self, _visit: &mut dyn FnMut(BorTag)) {
         // No tags here.
     }
 }
@@ -1220,7 +1220,7 @@ pub struct GlobalState {
 }
 
 impl VisitTags for GlobalState {
-    fn visit_tags(&self, _visit: &mut dyn FnMut(SbTag)) {
+    fn visit_tags(&self, _visit: &mut dyn FnMut(BorTag)) {
         // We don't have any tags.
     }
 }
index eb42cdf80abbeb5de883a9dc009948fc5777f2df..9c9d505297c2dd88bb4bff1f4893ca31e79eba68 100644 (file)
@@ -45,7 +45,7 @@ pub(super) struct InitOnce<'mir, 'tcx> {
 }
 
 impl<'mir, 'tcx> VisitTags for InitOnce<'mir, 'tcx> {
-    fn visit_tags(&self, visit: &mut dyn FnMut(SbTag)) {
+    fn visit_tags(&self, visit: &mut dyn FnMut(BorTag)) {
         for waiter in self.waiters.iter() {
             waiter.callback.visit_tags(visit);
         }
index dc4b435b7101ca1bad35fee51959de80b3691f81..402c9ce6fc9af927e9331eafd3ea9056f7f34c18 100644 (file)
@@ -181,7 +181,7 @@ pub(crate) struct SynchronizationState<'mir, 'tcx> {
 }
 
 impl<'mir, 'tcx> VisitTags for SynchronizationState<'mir, 'tcx> {
-    fn visit_tags(&self, visit: &mut dyn FnMut(SbTag)) {
+    fn visit_tags(&self, visit: &mut dyn FnMut(BorTag)) {
         for init_once in self.init_onces.iter() {
             init_once.visit_tags(visit);
         }
index dacb3a9b88f8f660f67bb234c552f7fbf90960f3..03f9ed351fb694db10a0d7e7f9a081db80bc29b8 100644 (file)
@@ -3,6 +3,7 @@
 use std::cell::RefCell;
 use std::collections::hash_map::Entry;
 use std::num::TryFromIntError;
+use std::task::Poll;
 use std::time::{Duration, SystemTime};
 
 use log::trace;
 
 use crate::concurrency::data_race;
 use crate::concurrency::sync::SynchronizationState;
+use crate::shims::tls;
 use crate::*;
 
 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
-pub enum SchedulingAction {
+enum SchedulingAction {
     /// Execute step on the active thread.
     ExecuteStep,
     /// Execute a timeout callback.
     ExecuteTimeoutCallback,
-    /// Execute destructors of the active thread.
-    ExecuteDtors,
-    /// Stop the program.
-    Stop,
+    /// Wait for a bit, until there is a timeout to be called.
+    Sleep(Duration),
 }
 
 /// Trait for callbacks that can be executed when some event happens, such as after a timeout.
@@ -41,9 +41,6 @@ pub trait MachineCallback<'mir, 'tcx>: VisitTags {
 #[derive(Clone, Copy, Debug, PartialOrd, Ord, PartialEq, Eq, Hash)]
 pub struct ThreadId(u32);
 
-/// The main thread. When it terminates, the whole application terminates.
-const MAIN_THREAD: ThreadId = ThreadId(0);
-
 impl ThreadId {
     pub fn to_u32(self) -> u32 {
         self.0
@@ -116,7 +113,13 @@ pub struct Thread<'mir, 'tcx> {
     thread_name: Option<Vec<u8>>,
 
     /// The virtual call stack.
-    stack: Vec<Frame<'mir, 'tcx, Provenance, FrameData<'tcx>>>,
+    stack: Vec<Frame<'mir, 'tcx, Provenance, FrameExtra<'tcx>>>,
+
+    /// The function to call when the stack ran empty, to figure out what to do next.
+    /// Conceptually, this is the interpreter implementation of the things that happen 'after' the
+    /// Rust language entry point for this thread returns (usually implemented by the C or OS runtime).
+    /// (`None` is an error, it means the callback has not been set up yet or is actively running.)
+    pub(crate) on_stack_empty: Option<StackEmptyCallback<'mir, 'tcx>>,
 
     /// The index of the topmost user-relevant frame in `stack`. This field must contain
     /// the value produced by `get_top_user_relevant_frame`.
@@ -137,19 +140,10 @@ pub struct Thread<'mir, 'tcx> {
     pub(crate) last_error: Option<MPlaceTy<'tcx, Provenance>>,
 }
 
-impl<'mir, 'tcx> Thread<'mir, 'tcx> {
-    /// Check if the thread is done executing (no more stack frames). If yes,
-    /// change the state to terminated and return `true`.
-    fn check_terminated(&mut self) -> bool {
-        if self.state == ThreadState::Enabled {
-            if self.stack.is_empty() {
-                self.state = ThreadState::Terminated;
-                return true;
-            }
-        }
-        false
-    }
+pub type StackEmptyCallback<'mir, 'tcx> =
+    Box<dyn FnMut(&mut MiriInterpCx<'mir, 'tcx>) -> InterpResult<'tcx, Poll<()>>>;
 
+impl<'mir, 'tcx> Thread<'mir, 'tcx> {
     /// Get the name of the current thread, or `<unnamed>` if it was not set.
     fn thread_name(&self) -> &[u8] {
         if let Some(ref thread_name) = self.thread_name { thread_name } else { b"<unnamed>" }
@@ -202,30 +196,23 @@ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
     }
 }
 
-impl<'mir, 'tcx> Default for Thread<'mir, 'tcx> {
-    fn default() -> Self {
+impl<'mir, 'tcx> Thread<'mir, 'tcx> {
+    fn new(name: Option<&str>, on_stack_empty: Option<StackEmptyCallback<'mir, 'tcx>>) -> Self {
         Self {
             state: ThreadState::Enabled,
-            thread_name: None,
+            thread_name: name.map(|name| Vec::from(name.as_bytes())),
             stack: Vec::new(),
             top_user_relevant_frame: None,
             join_status: ThreadJoinStatus::Joinable,
             panic_payload: None,
             last_error: None,
+            on_stack_empty,
         }
     }
 }
 
-impl<'mir, 'tcx> Thread<'mir, 'tcx> {
-    fn new(name: &str) -> Self {
-        let mut thread = Thread::default();
-        thread.thread_name = Some(Vec::from(name.as_bytes()));
-        thread
-    }
-}
-
 impl VisitTags for Thread<'_, '_> {
-    fn visit_tags(&self, visit: &mut dyn FnMut(SbTag)) {
+    fn visit_tags(&self, visit: &mut dyn FnMut(BorTag)) {
         let Thread {
             panic_payload,
             last_error,
@@ -234,6 +221,7 @@ fn visit_tags(&self, visit: &mut dyn FnMut(SbTag)) {
             state: _,
             thread_name: _,
             join_status: _,
+            on_stack_empty: _, // we assume the closure captures no GC-relevant state
         } = self;
 
         panic_payload.visit_tags(visit);
@@ -244,8 +232,8 @@ fn visit_tags(&self, visit: &mut dyn FnMut(SbTag)) {
     }
 }
 
-impl VisitTags for Frame<'_, '_, Provenance, FrameData<'_>> {
-    fn visit_tags(&self, visit: &mut dyn FnMut(SbTag)) {
+impl VisitTags for Frame<'_, '_, Provenance, FrameExtra<'_>> {
+    fn visit_tags(&self, visit: &mut dyn FnMut(BorTag)) {
         let Frame {
             return_place,
             locals,
@@ -327,24 +315,8 @@ pub struct ThreadManager<'mir, 'tcx> {
     timeout_callbacks: FxHashMap<ThreadId, TimeoutCallbackInfo<'mir, 'tcx>>,
 }
 
-impl<'mir, 'tcx> Default for ThreadManager<'mir, 'tcx> {
-    fn default() -> Self {
-        let mut threads = IndexVec::new();
-        // Create the main thread and add it to the list of threads.
-        threads.push(Thread::new("main"));
-        Self {
-            active_thread: ThreadId::new(0),
-            threads,
-            sync: SynchronizationState::default(),
-            thread_local_alloc_ids: Default::default(),
-            yield_active_thread: false,
-            timeout_callbacks: FxHashMap::default(),
-        }
-    }
-}
-
 impl VisitTags for ThreadManager<'_, '_> {
-    fn visit_tags(&self, visit: &mut dyn FnMut(SbTag)) {
+    fn visit_tags(&self, visit: &mut dyn FnMut(BorTag)) {
         let ThreadManager {
             threads,
             thread_local_alloc_ids,
@@ -367,8 +339,28 @@ fn visit_tags(&self, visit: &mut dyn FnMut(SbTag)) {
     }
 }
 
+impl<'mir, 'tcx> Default for ThreadManager<'mir, 'tcx> {
+    fn default() -> Self {
+        let mut threads = IndexVec::new();
+        // Create the main thread and add it to the list of threads.
+        threads.push(Thread::new(Some("main"), None));
+        Self {
+            active_thread: ThreadId::new(0),
+            threads,
+            sync: SynchronizationState::default(),
+            thread_local_alloc_ids: Default::default(),
+            yield_active_thread: false,
+            timeout_callbacks: FxHashMap::default(),
+        }
+    }
+}
+
 impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> {
-    pub(crate) fn init(ecx: &mut MiriInterpCx<'mir, 'tcx>) {
+    pub(crate) fn init(
+        ecx: &mut MiriInterpCx<'mir, 'tcx>,
+        on_main_stack_empty: StackEmptyCallback<'mir, 'tcx>,
+    ) {
+        ecx.machine.threads.threads[ThreadId::new(0)].on_stack_empty = Some(on_main_stack_empty);
         if ecx.tcx.sess.target.os.as_ref() != "windows" {
             // The main thread can *not* be joined on except on windows.
             ecx.machine.threads.threads[ThreadId::new(0)].join_status = ThreadJoinStatus::Detached;
@@ -393,27 +385,27 @@ fn set_thread_local_alloc(&self, def_id: DefId, ptr: Pointer<Provenance>) {
     }
 
     /// Borrow the stack of the active thread.
-    pub fn active_thread_stack(&self) -> &[Frame<'mir, 'tcx, Provenance, FrameData<'tcx>>] {
+    pub fn active_thread_stack(&self) -> &[Frame<'mir, 'tcx, Provenance, FrameExtra<'tcx>>] {
         &self.threads[self.active_thread].stack
     }
 
     /// Mutably borrow the stack of the active thread.
     fn active_thread_stack_mut(
         &mut self,
-    ) -> &mut Vec<Frame<'mir, 'tcx, Provenance, FrameData<'tcx>>> {
+    ) -> &mut Vec<Frame<'mir, 'tcx, Provenance, FrameExtra<'tcx>>> {
         &mut self.threads[self.active_thread].stack
     }
 
     pub fn all_stacks(
         &self,
-    ) -> impl Iterator<Item = &[Frame<'mir, 'tcx, Provenance, FrameData<'tcx>>]> {
+    ) -> impl Iterator<Item = &[Frame<'mir, 'tcx, Provenance, FrameExtra<'tcx>>]> {
         self.threads.iter().map(|t| &t.stack[..])
     }
 
     /// Create a new thread and returns its id.
-    fn create_thread(&mut self) -> ThreadId {
+    fn create_thread(&mut self, on_stack_empty: StackEmptyCallback<'mir, 'tcx>) -> ThreadId {
         let new_thread_id = ThreadId::new(self.threads.len());
-        self.threads.push(Default::default());
+        self.threads.push(Thread::new(None, Some(on_stack_empty)));
         new_thread_id
     }
 
@@ -458,7 +450,7 @@ fn enable_thread(&mut self, thread_id: ThreadId) {
     }
 
     /// Get a mutable borrow of the currently active thread.
-    fn active_thread_mut(&mut self) -> &mut Thread<'mir, 'tcx> {
+    pub fn active_thread_mut(&mut self) -> &mut Thread<'mir, 'tcx> {
         &mut self.threads[self.active_thread]
     }
 
@@ -669,18 +661,6 @@ fn thread_terminated(
     /// long as we can and switch only when we have to (the active thread was
     /// blocked, terminated, or has explicitly asked to be preempted).
     fn schedule(&mut self, clock: &Clock) -> InterpResult<'tcx, SchedulingAction> {
-        // Check whether the thread has **just** terminated (`check_terminated`
-        // checks whether the thread has popped all its stack and if yes, sets
-        // the thread state to terminated).
-        if self.threads[self.active_thread].check_terminated() {
-            return Ok(SchedulingAction::ExecuteDtors);
-        }
-        // If we get here again and the thread is *still* terminated, there are no more dtors to run.
-        if self.threads[MAIN_THREAD].state == ThreadState::Terminated {
-            // The main thread terminated; stop the program.
-            // We do *not* run TLS dtors of remaining threads, which seems to match rustc behavior.
-            return Ok(SchedulingAction::Stop);
-        }
         // This thread and the program can keep going.
         if self.threads[self.active_thread].state == ThreadState::Enabled
             && !self.yield_active_thread
@@ -688,18 +668,18 @@ fn schedule(&mut self, clock: &Clock) -> InterpResult<'tcx, SchedulingAction> {
             // The currently active thread is still enabled, just continue with it.
             return Ok(SchedulingAction::ExecuteStep);
         }
-        // The active thread yielded. Let's see if there are any timeouts to take care of. We do
-        // this *before* running any other thread, to ensure that timeouts "in the past" fire before
-        // any other thread can take an action. This ensures that for `pthread_cond_timedwait`, "an
-        // error is returned if [...] the absolute time specified by abstime has already been passed
-        // at the time of the call".
+        // The active thread yielded or got terminated. Let's see if there are any timeouts to take
+        // care of. We do this *before* running any other thread, to ensure that timeouts "in the
+        // past" fire before any other thread can take an action. This ensures that for
+        // `pthread_cond_timedwait`, "an error is returned if [...] the absolute time specified by
+        // abstime has already been passed at the time of the call".
         // <https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_cond_timedwait.html>
         let potential_sleep_time =
             self.timeout_callbacks.values().map(|info| info.call_time.get_wait_time(clock)).min();
         if potential_sleep_time == Some(Duration::new(0, 0)) {
             return Ok(SchedulingAction::ExecuteTimeoutCallback);
         }
-        // No callbacks scheduled, pick a regular thread to execute.
+        // No callbacks immediately scheduled, pick a regular thread to execute.
         // The active thread blocked or yielded. So we go search for another enabled thread.
         // Crucially, we start searching at the current active thread ID, rather than at 0, since we
         // want to avoid always scheduling threads 0 and 1 without ever making progress in thread 2.
@@ -730,15 +710,58 @@ fn schedule(&mut self, clock: &Clock) -> InterpResult<'tcx, SchedulingAction> {
             // All threads are currently blocked, but we have unexecuted
             // timeout_callbacks, which may unblock some of the threads. Hence,
             // sleep until the first callback.
-
-            clock.sleep(sleep_time);
-            Ok(SchedulingAction::ExecuteTimeoutCallback)
+            Ok(SchedulingAction::Sleep(sleep_time))
         } else {
             throw_machine_stop!(TerminationInfo::Deadlock);
         }
     }
 }
 
+impl<'mir, 'tcx: 'mir> EvalContextPrivExt<'mir, 'tcx> for MiriInterpCx<'mir, 'tcx> {}
+trait EvalContextPrivExt<'mir, 'tcx: 'mir>: MiriInterpCxExt<'mir, 'tcx> {
+    /// Execute a timeout callback on the callback's thread.
+    #[inline]
+    fn run_timeout_callback(&mut self) -> InterpResult<'tcx> {
+        let this = self.eval_context_mut();
+        let (thread, callback) = if let Some((thread, callback)) =
+            this.machine.threads.get_ready_callback(&this.machine.clock)
+        {
+            (thread, callback)
+        } else {
+            // get_ready_callback can return None if the computer's clock
+            // was shifted after calling the scheduler and before the call
+            // to get_ready_callback (see issue
+            // https://github.com/rust-lang/miri/issues/1763). In this case,
+            // just do nothing, which effectively just returns to the
+            // scheduler.
+            return Ok(());
+        };
+        // This back-and-forth with `set_active_thread` is here because of two
+        // design decisions:
+        // 1. Make the caller and not the callback responsible for changing
+        //    thread.
+        // 2. Make the scheduler the only place that can change the active
+        //    thread.
+        let old_thread = this.set_active_thread(thread);
+        callback.call(this)?;
+        this.set_active_thread(old_thread);
+        Ok(())
+    }
+
+    #[inline]
+    fn run_on_stack_empty(&mut self) -> InterpResult<'tcx, Poll<()>> {
+        let this = self.eval_context_mut();
+        let mut callback = this
+            .active_thread_mut()
+            .on_stack_empty
+            .take()
+            .expect("`on_stack_empty` not set up, or already running");
+        let res = callback(this)?;
+        this.active_thread_mut().on_stack_empty = Some(callback);
+        Ok(res)
+    }
+}
+
 // Public interface to thread management.
 impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriInterpCx<'mir, 'tcx> {}
 pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
@@ -773,18 +796,9 @@ fn get_or_create_thread_local_alloc(
         }
     }
 
+    /// Start a regular (non-main) thread.
     #[inline]
-    fn create_thread(&mut self) -> ThreadId {
-        let this = self.eval_context_mut();
-        let id = this.machine.threads.create_thread();
-        if let Some(data_race) = &mut this.machine.data_race {
-            data_race.thread_created(&this.machine.threads, id);
-        }
-        id
-    }
-
-    #[inline]
-    fn start_thread(
+    fn start_regular_thread(
         &mut self,
         thread: Option<MPlaceTy<'tcx, Provenance>>,
         start_routine: Pointer<Option<Provenance>>,
@@ -795,7 +809,13 @@ fn start_thread(
         let this = self.eval_context_mut();
 
         // Create the new thread
-        let new_thread_id = this.create_thread();
+        let new_thread_id = this.machine.threads.create_thread({
+            let mut state = tls::TlsDtorsState::default();
+            Box::new(move |m| state.on_stack_empty(m))
+        });
+        if let Some(data_race) = &mut this.machine.data_race {
+            data_race.thread_created(&this.machine.threads, new_thread_id);
+        }
 
         // Write the current thread-id, switch to the next thread later
         // to treat this write operation as occuring on the current thread.
@@ -888,12 +908,6 @@ fn get_total_thread_count(&self) -> usize {
         this.machine.threads.get_total_thread_count()
     }
 
-    #[inline]
-    fn has_terminated(&self, thread_id: ThreadId) -> bool {
-        let this = self.eval_context_ref();
-        this.machine.threads.has_terminated(thread_id)
-    }
-
     #[inline]
     fn have_all_terminated(&self) -> bool {
         let this = self.eval_context_ref();
@@ -907,7 +921,7 @@ fn enable_thread(&mut self, thread_id: ThreadId) {
     }
 
     #[inline]
-    fn active_thread_stack(&self) -> &[Frame<'mir, 'tcx, Provenance, FrameData<'tcx>>] {
+    fn active_thread_stack(&self) -> &[Frame<'mir, 'tcx, Provenance, FrameExtra<'tcx>>] {
         let this = self.eval_context_ref();
         this.machine.threads.active_thread_stack()
     }
@@ -915,7 +929,7 @@ fn active_thread_stack(&self) -> &[Frame<'mir, 'tcx, Provenance, FrameData<'tcx>
     #[inline]
     fn active_thread_stack_mut(
         &mut self,
-    ) -> &mut Vec<Frame<'mir, 'tcx, Provenance, FrameData<'tcx>>> {
+    ) -> &mut Vec<Frame<'mir, 'tcx, Provenance, FrameExtra<'tcx>>> {
         let this = self.eval_context_mut();
         this.machine.threads.active_thread_stack_mut()
     }
@@ -943,26 +957,22 @@ fn get_thread_name<'c>(&'c self, thread: ThreadId) -> &'c [u8]
     where
         'mir: 'c,
     {
-        let this = self.eval_context_ref();
-        this.machine.threads.get_thread_name(thread)
+        self.eval_context_ref().machine.threads.get_thread_name(thread)
     }
 
     #[inline]
     fn block_thread(&mut self, thread: ThreadId) {
-        let this = self.eval_context_mut();
-        this.machine.threads.block_thread(thread);
+        self.eval_context_mut().machine.threads.block_thread(thread);
     }
 
     #[inline]
     fn unblock_thread(&mut self, thread: ThreadId) {
-        let this = self.eval_context_mut();
-        this.machine.threads.unblock_thread(thread);
+        self.eval_context_mut().machine.threads.unblock_thread(thread);
     }
 
     #[inline]
     fn yield_active_thread(&mut self) {
-        let this = self.eval_context_mut();
-        this.machine.threads.yield_active_thread();
+        self.eval_context_mut().machine.threads.yield_active_thread();
     }
 
     #[inline]
@@ -995,49 +1005,42 @@ fn unregister_timeout_callback_if_exists(&mut self, thread: ThreadId) {
         this.machine.threads.unregister_timeout_callback_if_exists(thread);
     }
 
-    /// Execute a timeout callback on the callback's thread.
-    #[inline]
-    fn run_timeout_callback(&mut self) -> InterpResult<'tcx> {
-        let this = self.eval_context_mut();
-        let (thread, callback) = if let Some((thread, callback)) =
-            this.machine.threads.get_ready_callback(&this.machine.clock)
-        {
-            (thread, callback)
-        } else {
-            // get_ready_callback can return None if the computer's clock
-            // was shifted after calling the scheduler and before the call
-            // to get_ready_callback (see issue
-            // https://github.com/rust-lang/miri/issues/1763). In this case,
-            // just do nothing, which effectively just returns to the
-            // scheduler.
-            return Ok(());
-        };
-        // This back-and-forth with `set_active_thread` is here because of two
-        // design decisions:
-        // 1. Make the caller and not the callback responsible for changing
-        //    thread.
-        // 2. Make the scheduler the only place that can change the active
-        //    thread.
-        let old_thread = this.set_active_thread(thread);
-        callback.call(this)?;
-        this.set_active_thread(old_thread);
-        Ok(())
-    }
-
-    /// Decide which action to take next and on which thread.
-    #[inline]
-    fn schedule(&mut self) -> InterpResult<'tcx, SchedulingAction> {
+    /// Run the core interpreter loop. Returns only when an interrupt occurs (an error or program
+    /// termination).
+    fn run_threads(&mut self) -> InterpResult<'tcx, !> {
         let this = self.eval_context_mut();
-        this.machine.threads.schedule(&this.machine.clock)
+        loop {
+            match this.machine.threads.schedule(&this.machine.clock)? {
+                SchedulingAction::ExecuteStep => {
+                    if !this.step()? {
+                        // See if this thread can do something else.
+                        match this.run_on_stack_empty()? {
+                            Poll::Pending => {} // keep going
+                            Poll::Ready(()) => this.terminate_active_thread()?,
+                        }
+                    }
+                }
+                SchedulingAction::ExecuteTimeoutCallback => {
+                    this.run_timeout_callback()?;
+                }
+                SchedulingAction::Sleep(duration) => {
+                    this.machine.clock.sleep(duration);
+                }
+            }
+        }
     }
 
     /// Handles thread termination of the active thread: wakes up threads joining on this one,
     /// and deallocated thread-local statics.
     ///
-    /// This is called from `tls.rs` after handling the TLS dtors.
+    /// This is called by the eval loop when a thread's on_stack_empty returns `Ready`.
     #[inline]
-    fn thread_terminated(&mut self) -> InterpResult<'tcx> {
+    fn terminate_active_thread(&mut self) -> InterpResult<'tcx> {
         let this = self.eval_context_mut();
+        let thread = this.active_thread_mut();
+        assert!(thread.stack.is_empty(), "only threads with an empty stack can be terminated");
+        thread.state = ThreadState::Terminated;
+
         for ptr in this.machine.threads.thread_terminated(this.machine.data_race.as_mut()) {
             this.deallocate_ptr(ptr.into(), None, MiriMemoryKind::Tls.into())?;
         }
index e7e5b35ac2cd2aa6143b1242dfa222b1b7bdbd44..ba04991a5889d8bc5f7454f6558753af90e67f0b 100644 (file)
@@ -404,67 +404,49 @@ fn assert_order(l: &[VTimestamp], r: &[VTimestamp], o: Option<Ordering>) {
         assert_eq!(
             alt_compare,
             o.map(Ordering::reverse),
-            "Invalid alt comparison\n l: {:?}\n r: {:?}",
-            l,
-            r
+            "Invalid alt comparison\n l: {l:?}\n r: {r:?}"
         );
 
         //Test operators with faster implementations
         assert_eq!(
             matches!(compare, Some(Ordering::Less)),
             l < r,
-            "Invalid (<):\n l: {:?}\n r: {:?}",
-            l,
-            r
+            "Invalid (<):\n l: {l:?}\n r: {r:?}"
         );
         assert_eq!(
             matches!(compare, Some(Ordering::Less) | Some(Ordering::Equal)),
             l <= r,
-            "Invalid (<=):\n l: {:?}\n r: {:?}",
-            l,
-            r
+            "Invalid (<=):\n l: {l:?}\n r: {r:?}"
         );
         assert_eq!(
             matches!(compare, Some(Ordering::Greater)),
             l > r,
-            "Invalid (>):\n l: {:?}\n r: {:?}",
-            l,
-            r
+            "Invalid (>):\n l: {l:?}\n r: {r:?}"
         );
         assert_eq!(
             matches!(compare, Some(Ordering::Greater) | Some(Ordering::Equal)),
             l >= r,
-            "Invalid (>=):\n l: {:?}\n r: {:?}",
-            l,
-            r
+            "Invalid (>=):\n l: {l:?}\n r: {r:?}"
         );
         assert_eq!(
             matches!(alt_compare, Some(Ordering::Less)),
             r < l,
-            "Invalid alt (<):\n l: {:?}\n r: {:?}",
-            l,
-            r
+            "Invalid alt (<):\n l: {l:?}\n r: {r:?}"
         );
         assert_eq!(
             matches!(alt_compare, Some(Ordering::Less) | Some(Ordering::Equal)),
             r <= l,
-            "Invalid alt (<=):\n l: {:?}\n r: {:?}",
-            l,
-            r
+            "Invalid alt (<=):\n l: {l:?}\n r: {r:?}"
         );
         assert_eq!(
             matches!(alt_compare, Some(Ordering::Greater)),
             r > l,
-            "Invalid alt (>):\n l: {:?}\n r: {:?}",
-            l,
-            r
+            "Invalid alt (>):\n l: {l:?}\n r: {r:?}"
         );
         assert_eq!(
             matches!(alt_compare, Some(Ordering::Greater) | Some(Ordering::Equal)),
             r >= l,
-            "Invalid alt (>=):\n l: {:?}\n r: {:?}",
-            l,
-            r
+            "Invalid alt (>=):\n l: {l:?}\n r: {r:?}"
         );
     }
 }
index f2a36572954948d4b888ac05e0b38fecf263bac3..391681444d9ba03ce2c26b413a77ebe7eee2acf4 100644 (file)
@@ -93,7 +93,7 @@
     vector_clock::{VClock, VTimestamp, VectorIdx},
 };
 
-pub type AllocExtra = StoreBufferAlloc;
+pub type AllocState = StoreBufferAlloc;
 
 // Each store buffer must be bounded otherwise it will grow indefinitely.
 // However, bounding the store buffer means restricting the amount of weak
@@ -109,7 +109,7 @@ pub struct StoreBufferAlloc {
 }
 
 impl VisitTags for StoreBufferAlloc {
-    fn visit_tags(&self, visit: &mut dyn FnMut(SbTag)) {
+    fn visit_tags(&self, visit: &mut dyn FnMut(BorTag)) {
         let Self { store_buffers } = self;
         for val in store_buffers
             .borrow()
index 7658cea10f9f8376af991b8958acaff15661503b..c22ac50e4557e5fe107d942d46ab384abb495479 100644 (file)
@@ -6,12 +6,15 @@
 use rustc_span::{source_map::DUMMY_SP, SpanData, Symbol};
 use rustc_target::abi::{Align, Size};
 
-use crate::stacked_borrows::{diagnostics::TagHistory, AccessKind};
+use crate::borrow_tracker::stacked_borrows::diagnostics::TagHistory;
 use crate::*;
 
 /// Details of premature program termination.
 pub enum TerminationInfo {
-    Exit(i64),
+    Exit {
+        code: i64,
+        leak_check: bool,
+    },
     Abort(String),
     UnsupportedInIsolation(String),
     StackedBorrowsUb {
@@ -38,7 +41,7 @@ impl fmt::Display for TerminationInfo {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         use TerminationInfo::*;
         match self {
-            Exit(code) => write!(f, "the evaluated program completed with exit code {code}"),
+            Exit { code, .. } => write!(f, "the evaluated program completed with exit code {code}"),
             Abort(msg) => write!(f, "{msg}"),
             UnsupportedInIsolation(msg) => write!(f, "{msg}"),
             Int2PtrWithStrictProvenance =>
@@ -60,13 +63,12 @@ impl MachineStopType for TerminationInfo {}
 
 /// Miri specific diagnostics
 pub enum NonHaltingDiagnostic {
-    /// (new_tag, new_kind, (alloc_id, base_offset, orig_tag))
+    /// (new_tag, new_perm, (alloc_id, base_offset, orig_tag))
     ///
-    /// new_kind is `None` for base tags.
+    /// new_perm is `None` for base tags.
     CreatedPointerTag(NonZeroU64, Option<String>, Option<(AllocId, AllocRange, ProvenanceExtra)>),
-    /// This `Item` was popped from the borrow stack, either due to an access with the given tag or
-    /// a deallocation when the second argument is `None`.
-    PoppedPointerTag(Item, Option<(ProvenanceExtra, AccessKind)>),
+    /// This `Item` was popped from the borrow stack. The string explains the reason.
+    PoppedPointerTag(Item, String),
     CreatedCallId(CallId),
     CreatedAlloc(AllocId, Size, Align, MemoryKind<MiriMemoryKind>),
     FreedAlloc(AllocId),
@@ -148,11 +150,11 @@ fn prune_stacktrace<'tcx>(
 
 /// Emit a custom diagnostic without going through the miri-engine machinery.
 ///
-/// Returns `Some` if this was regular program termination with a given exit code, `None` otherwise.
+/// Returns `Some` if this was regular program termination with a given exit code and a `bool` indicating whether a leak check should happen; `None` otherwise.
 pub fn report_error<'tcx, 'mir>(
     ecx: &InterpCx<'mir, 'tcx, MiriMachine<'mir, 'tcx>>,
     e: InterpErrorInfo<'tcx>,
-) -> Option<i64> {
+) -> Option<(i64, bool)> {
     use InterpError::*;
 
     let mut msg = vec![];
@@ -161,7 +163,7 @@ pub fn report_error<'tcx, 'mir>(
         let info = info.downcast_ref::<TerminationInfo>().expect("invalid MachineStop payload");
         use TerminationInfo::*;
         let title = match info {
-            Exit(code) => return Some(*code),
+            Exit { code, leak_check } => return Some((*code, *leak_check)),
             Abort(_) => Some("abnormal termination"),
             UnsupportedInIsolation(_) | Int2PtrWithStrictProvenance =>
                 Some("unsupported operation"),
@@ -362,7 +364,9 @@ fn report_msg<'tcx>(
         if is_local && idx > 0 {
             err.span_note(frame_info.span, &frame_info.to_string());
         } else {
-            err.note(&frame_info.to_string());
+            let sm = sess.source_map();
+            let span = sm.span_to_embeddable_string(frame_info.span);
+            err.note(format!("{frame_info} at {span}"));
         }
     }
 
@@ -391,20 +395,12 @@ pub fn emit_diagnostic(&self, e: NonHaltingDiagnostic) {
 
         let msg = match &e {
             CreatedPointerTag(tag, None, _) => format!("created base tag {tag:?}"),
-            CreatedPointerTag(tag, Some(kind), None) => format!("created {tag:?} for {kind}"),
-            CreatedPointerTag(tag, Some(kind), Some((alloc_id, range, orig_tag))) =>
+            CreatedPointerTag(tag, Some(perm), None) => format!("created {tag:?} with {perm} derived from unknown tag"),
+            CreatedPointerTag(tag, Some(perm), Some((alloc_id, range, orig_tag))) =>
                 format!(
-                    "created tag {tag:?} for {kind} at {alloc_id:?}{range:?} derived from {orig_tag:?}"
+                    "created tag {tag:?} with {perm} at {alloc_id:?}{range:?} derived from {orig_tag:?}"
                 ),
-            PoppedPointerTag(item, tag) =>
-                match tag {
-                    None => format!("popped tracked tag for item {item:?} due to deallocation",),
-                    Some((tag, access)) => {
-                        format!(
-                            "popped tracked tag for item {item:?} due to {access:?} access for {tag:?}",
-                        )
-                    }
-                },
+            PoppedPointerTag(item, cause) => format!("popped tracked tag for item {item:?}{cause}"),
             CreatedCallId(id) => format!("function call with id {id}"),
             CreatedAlloc(AllocId(id), size, align, kind) =>
                 format!(
index 363b647d6c684fd6e95e04a7244f7217c1073d4e..7b4973f3b9daf2bdf3bce7e7f19bfd25db85c17c 100644 (file)
@@ -4,10 +4,12 @@
 use std::iter;
 use std::panic::{self, AssertUnwindSafe};
 use std::path::PathBuf;
+use std::task::Poll;
 use std::thread;
 
 use log::info;
 
+use crate::borrow_tracker::RetagFields;
 use rustc_data_structures::fx::FxHashSet;
 use rustc_hir::def::Namespace;
 use rustc_hir::def_id::DefId;
 
 use rustc_session::config::EntryFnType;
 
+use crate::shims::tls;
 use crate::*;
 
+/// When the main thread would exit, we will yield to any other thread that is ready to execute.
+/// But we must only do that a finite number of times, or a background thread running `loop {}`
+/// will hang the program.
+const MAIN_THREAD_YIELDS_AT_SHUTDOWN: u32 = 256;
+
 #[derive(Copy, Clone, Debug, PartialEq)]
 pub enum AlignmentCheck {
     /// Do not check alignment.
@@ -80,7 +88,7 @@ pub struct MiriConfig {
     /// Determine if validity checking is enabled.
     pub validate: bool,
     /// Determines if Stacked Borrows is enabled.
-    pub stacked_borrows: bool,
+    pub borrow_tracker: Option<BorrowTrackerMethod>,
     /// Controls alignment checking.
     pub check_alignment: AlignmentCheck,
     /// Controls function [ABI](Abi) checking.
@@ -96,7 +104,7 @@ pub struct MiriConfig {
     /// The seed to use when non-determinism or randomness are required (e.g. ptr-to-int cast, `getrandom()`).
     pub seed: Option<u64>,
     /// The stacked borrows pointer ids to report about
-    pub tracked_pointer_tags: FxHashSet<SbTag>,
+    pub tracked_pointer_tags: FxHashSet<BorTag>,
     /// The stacked borrows call IDs to report about
     pub tracked_call_ids: FxHashSet<CallId>,
     /// The allocation ids to report about.
@@ -131,7 +139,7 @@ pub struct MiriConfig {
     /// The location of a shared object file to load when calling external functions
     /// FIXME! consider allowing users to specify paths to multiple SO files, or to a directory
     pub external_so_file: Option<PathBuf>,
-    /// Run a garbage collector for SbTags every N basic blocks.
+    /// Run a garbage collector for BorTags every N basic blocks.
     pub gc_interval: u32,
     /// The number of CPUs to be reported by miri.
     pub num_cpus: u32,
@@ -142,7 +150,7 @@ fn default() -> MiriConfig {
         MiriConfig {
             env: vec![],
             validate: true,
-            stacked_borrows: true,
+            borrow_tracker: Some(BorrowTrackerMethod::StackedBorrows),
             check_alignment: AlignmentCheck::Int,
             check_abi: true,
             isolated_op: IsolatedOp::Reject(RejectOpWith::Abort),
@@ -172,17 +180,79 @@ fn default() -> MiriConfig {
     }
 }
 
-/// Returns a freshly created `InterpCx`, along with an `MPlaceTy` representing
-/// the location where the return value of the `start` function will be
-/// written to.
+/// The state of the main thread. Implementation detail of `on_main_stack_empty`.
+#[derive(Default, Debug)]
+enum MainThreadState {
+    #[default]
+    Running,
+    TlsDtors(tls::TlsDtorsState),
+    Yield {
+        remaining: u32,
+    },
+    Done,
+}
+
+impl MainThreadState {
+    fn on_main_stack_empty<'tcx>(
+        &mut self,
+        this: &mut MiriInterpCx<'_, 'tcx>,
+    ) -> InterpResult<'tcx, Poll<()>> {
+        use MainThreadState::*;
+        match self {
+            Running => {
+                *self = TlsDtors(Default::default());
+            }
+            TlsDtors(state) =>
+                match state.on_stack_empty(this)? {
+                    Poll::Pending => {} // just keep going
+                    Poll::Ready(()) => {
+                        // Give background threads a chance to finish by yielding the main thread a
+                        // couple of times -- but only if we would also preempt threads randomly.
+                        if this.machine.preemption_rate > 0.0 {
+                            // There is a non-zero chance they will yield back to us often enough to
+                            // make Miri terminate eventually.
+                            *self = Yield { remaining: MAIN_THREAD_YIELDS_AT_SHUTDOWN };
+                        } else {
+                            // The other threads did not get preempted, so no need to yield back to
+                            // them.
+                            *self = Done;
+                        }
+                    }
+                },
+            Yield { remaining } =>
+                match remaining.checked_sub(1) {
+                    None => *self = Done,
+                    Some(new_remaining) => {
+                        *remaining = new_remaining;
+                        this.yield_active_thread();
+                    }
+                },
+            Done => {
+                // Figure out exit code.
+                let ret_place = MPlaceTy::from_aligned_ptr(
+                    this.machine.main_fn_ret_place.unwrap().ptr,
+                    this.machine.layouts.isize,
+                );
+                let exit_code = this.read_scalar(&ret_place.into())?.to_machine_isize(this)?;
+                // Need to call this ourselves since we are not going to return to the scheduler
+                // loop, and we want the main thread TLS to not show up as memory leaks.
+                this.terminate_active_thread()?;
+                // Stop interpreter loop.
+                throw_machine_stop!(TerminationInfo::Exit { code: exit_code, leak_check: true });
+            }
+        }
+        Ok(Poll::Pending)
+    }
+}
+
+/// Returns a freshly created `InterpCx`.
 /// Public because this is also used by `priroda`.
 pub fn create_ecx<'mir, 'tcx: 'mir>(
     tcx: TyCtxt<'tcx>,
     entry_id: DefId,
     entry_type: EntryFnType,
     config: &MiriConfig,
-) -> InterpResult<'tcx, (InterpCx<'mir, 'tcx, MiriMachine<'mir, 'tcx>>, MPlaceTy<'tcx, Provenance>)>
-{
+) -> InterpResult<'tcx, InterpCx<'mir, 'tcx, MiriMachine<'mir, 'tcx>>> {
     let param_env = ty::ParamEnv::reveal_all();
     let layout_cx = LayoutCx { tcx, param_env };
     let mut ecx = InterpCx::new(
@@ -193,7 +263,11 @@ pub fn create_ecx<'mir, 'tcx: 'mir>(
     );
 
     // Some parts of initialization require a full `InterpCx`.
-    MiriMachine::late_init(&mut ecx, config)?;
+    MiriMachine::late_init(&mut ecx, config, {
+        let mut state = MainThreadState::default();
+        // Cannot capture anything GC-relevant here.
+        Box::new(move |m| state.on_main_stack_empty(m))
+    })?;
 
     // Make sure we have MIR. We check MIR for some stable monomorphic function in libcore.
     let sentinel = ecx.try_resolve_path(&["core", "ascii", "escape_default"], Namespace::ValueNS);
@@ -274,6 +348,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>(
 
     // Return place (in static memory so that it does not count as leak).
     let ret_place = ecx.allocate(ecx.machine.layouts.isize, MiriMemoryKind::Machine.into())?;
+    ecx.machine.main_fn_ret_place = Some(*ret_place);
     // Call start function.
 
     match entry_type {
@@ -321,7 +396,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>(
         }
     }
 
-    Ok((ecx, ret_place))
+    Ok(ecx)
 }
 
 /// Evaluates the entry function specified by `entry_id`.
@@ -337,7 +412,7 @@ pub fn eval_entry<'tcx>(
     // Copy setting before we move `config`.
     let ignore_leaks = config.ignore_leaks;
 
-    let (mut ecx, ret_place) = match create_ecx(tcx, entry_id, entry_type, &config) {
+    let mut ecx = match create_ecx(tcx, entry_id, entry_type, &config) {
         Ok(v) => v,
         Err(err) => {
             err.print_backtrace();
@@ -346,34 +421,17 @@ pub fn eval_entry<'tcx>(
     };
 
     // Perform the main execution.
-    let res: thread::Result<InterpResult<'_, i64>> = panic::catch_unwind(AssertUnwindSafe(|| {
-        // Main loop.
-        loop {
-            match ecx.schedule()? {
-                SchedulingAction::ExecuteStep => {
-                    assert!(ecx.step()?, "a terminated thread was scheduled for execution");
-                }
-                SchedulingAction::ExecuteTimeoutCallback => {
-                    ecx.run_timeout_callback()?;
-                }
-                SchedulingAction::ExecuteDtors => {
-                    // This will either enable the thread again (so we go back
-                    // to `ExecuteStep`), or determine that this thread is done
-                    // for good.
-                    ecx.schedule_next_tls_dtor_for_active_thread()?;
-                }
-                SchedulingAction::Stop => {
-                    break;
-                }
-            }
-        }
-        let return_code = ecx.read_scalar(&ret_place.into())?.to_machine_isize(&ecx)?;
-        Ok(return_code)
-    }));
+    let res: thread::Result<InterpResult<'_, !>> =
+        panic::catch_unwind(AssertUnwindSafe(|| ecx.run_threads()));
     let res = res.unwrap_or_else(|panic_payload| {
         ecx.handle_ice();
         panic::resume_unwind(panic_payload)
     });
+    let res = match res {
+        Err(res) => res,
+        // `Ok` can never happen
+        Ok(never) => match never {},
+    };
 
     // Machine cleanup. Only do this if all threads have terminated; threads that are still running
     // might cause Stacked Borrows errors (https://github.com/rust-lang/miri/issues/2396).
@@ -386,32 +444,26 @@ pub fn eval_entry<'tcx>(
     }
 
     // Process the result.
-    match res {
-        Ok(return_code) => {
-            if !ignore_leaks {
-                // Check for thread leaks.
-                if !ecx.have_all_terminated() {
-                    tcx.sess.err(
-                        "the main thread terminated without waiting for all remaining threads",
-                    );
-                    tcx.sess.note_without_error("pass `-Zmiri-ignore-leaks` to disable this check");
-                    return None;
-                }
-                // Check for memory leaks.
-                info!("Additonal static roots: {:?}", ecx.machine.static_roots);
-                let leaks = ecx.leak_report(&ecx.machine.static_roots);
-                if leaks != 0 {
-                    tcx.sess.err("the evaluated program leaked memory");
-                    tcx.sess.note_without_error("pass `-Zmiri-ignore-leaks` to disable this check");
-                    // Ignore the provided return code - let the reported error
-                    // determine the return code.
-                    return None;
-                }
-            }
-            Some(return_code)
+    let (return_code, leak_check) = report_error(&ecx, res)?;
+    if leak_check && !ignore_leaks {
+        // Check for thread leaks.
+        if !ecx.have_all_terminated() {
+            tcx.sess.err("the main thread terminated without waiting for all remaining threads");
+            tcx.sess.note_without_error("pass `-Zmiri-ignore-leaks` to disable this check");
+            return None;
+        }
+        // Check for memory leaks.
+        info!("Additonal static roots: {:?}", ecx.machine.static_roots);
+        let leaks = ecx.leak_report(&ecx.machine.static_roots);
+        if leaks != 0 {
+            tcx.sess.err("the evaluated program leaked memory");
+            tcx.sess.note_without_error("pass `-Zmiri-ignore-leaks` to disable this check");
+            // Ignore the provided return code - let the reported error
+            // determine the return code.
+            return None;
         }
-        Err(e) => report_error(&ecx, e),
     }
+    Some(return_code)
 }
 
 /// Turns an array of arguments into a Windows command line string.
index f0d8b6768810c720fc7c367d90de6e9ef68c852e..7fb2539ca5a678824649211f3b9bb4b3309467ee 100644 (file)
@@ -554,9 +554,7 @@ fn assert_target_os(&self, target_os: &str, name: &str) {
         assert_eq!(
             self.eval_context_ref().tcx.sess.target.os,
             target_os,
-            "`{}` is only available on the `{}` target OS",
-            name,
-            target_os,
+            "`{name}` is only available on the `{target_os}` target OS",
         )
     }
 
@@ -566,8 +564,7 @@ fn assert_target_os(&self, target_os: &str, name: &str) {
     fn assert_target_os_is_unix(&self, name: &str) {
         assert!(
             target_os_is_unix(self.eval_context_ref().tcx.sess.target.os.as_ref()),
-            "`{}` is only available for supported UNIX family targets",
-            name,
+            "`{name}` is only available for supported UNIX family targets",
         );
     }
 
@@ -988,7 +985,7 @@ pub fn caller_span(&self) -> Span {
         self.stack()[frame_idx].current_span()
     }
 
-    fn stack(&self) -> &[Frame<'mir, 'tcx, Provenance, machine::FrameData<'tcx>>] {
+    fn stack(&self) -> &[Frame<'mir, 'tcx, Provenance, machine::FrameExtra<'tcx>>] {
         self.threads.active_thread_stack()
     }
 
@@ -1019,8 +1016,7 @@ pub fn check_arg_count<'a, 'tcx, const N: usize>(
 
 pub fn isolation_abort_error<'tcx>(name: &str) -> InterpResult<'tcx> {
     throw_machine_stop!(TerminationInfo::UnsupportedInIsolation(format!(
-        "{} not available when isolation is enabled",
-        name,
+        "{name} not available when isolation is enabled",
     )))
 }
 
index 9722b7643e426cea90324dc1f7258816a29d7104..c26828b11e0e1322e29fdb0d5069966f1237590f 100644 (file)
@@ -45,7 +45,7 @@ pub struct GlobalStateInner {
 }
 
 impl VisitTags for GlobalStateInner {
-    fn visit_tags(&self, _visit: &mut dyn FnMut(SbTag)) {
+    fn visit_tags(&self, _visit: &mut dyn FnMut(BorTag)) {
         // Nothing to visit here.
     }
 }
@@ -105,15 +105,15 @@ fn alloc_id_from_addr(ecx: &MiriInterpCx<'mir, 'tcx>, addr: u64) -> Option<Alloc
     pub fn expose_ptr(
         ecx: &mut MiriInterpCx<'mir, 'tcx>,
         alloc_id: AllocId,
-        sb: SbTag,
+        tag: BorTag,
     ) -> InterpResult<'tcx> {
         let global_state = ecx.machine.intptrcast.get_mut();
         // In strict mode, we don't need this, so we can save some cycles by not tracking it.
         if global_state.provenance_mode != ProvenanceMode::Strict {
             trace!("Exposing allocation id {alloc_id:?}");
             global_state.exposed.insert(alloc_id);
-            if ecx.machine.stacked_borrows.is_some() {
-                ecx.expose_tag(alloc_id, sb)?;
+            if ecx.machine.borrow_tracker.is_some() {
+                ecx.expose_tag(alloc_id, tag)?;
             }
         }
         Ok(())
index 8913f8aa10fcdb962e927e93858cb5f6f21ae1b6..42519797976b7795805ca245c1ccd0c3ec80640d 100644 (file)
@@ -53,6 +53,7 @@
 extern crate rustc_span;
 extern crate rustc_target;
 
+mod borrow_tracker;
 mod clock;
 mod concurrency;
 mod diagnostics;
@@ -64,7 +65,6 @@
 mod operator;
 mod range_map;
 mod shims;
-mod stacked_borrows;
 mod tag_gc;
 
 // Establish a "crate-wide prelude": we often import `crate::*`.
 pub use crate::shims::os_str::EvalContextExt as _;
 pub use crate::shims::panic::{CatchUnwindData, EvalContextExt as _};
 pub use crate::shims::time::EvalContextExt as _;
-pub use crate::shims::tls::{EvalContextExt as _, TlsData};
+pub use crate::shims::tls::TlsData;
 pub use crate::shims::EvalContextExt as _;
 
+pub use crate::borrow_tracker::stacked_borrows::{
+    EvalContextExt as _, Item, Permission, Stack, Stacks,
+};
+pub use crate::borrow_tracker::{
+    BorTag, BorrowTrackerMethod, CallId, EvalContextExt as _, RetagFields,
+};
 pub use crate::clock::{Clock, Instant};
 pub use crate::concurrency::{
     data_race::{AtomicFenceOrd, AtomicReadOrd, AtomicRwOrd, AtomicWriteOrd, EvalContextExt as _},
     init_once::{EvalContextExt as _, InitOnceId},
     sync::{CondvarId, EvalContextExt as _, MutexId, RwLockId, SyncId},
-    thread::{EvalContextExt as _, SchedulingAction, ThreadId, ThreadManager, ThreadState, Time},
+    thread::{EvalContextExt as _, StackEmptyCallback, ThreadId, ThreadManager, Time},
 };
 pub use crate::diagnostics::{
     report_error, EvalContextExt as _, NonHaltingDiagnostic, TerminationInfo,
 pub use crate::helpers::EvalContextExt as _;
 pub use crate::intptrcast::ProvenanceMode;
 pub use crate::machine::{
-    AllocExtra, FrameData, MiriInterpCx, MiriInterpCxExt, MiriMachine, MiriMemoryKind,
+    AllocExtra, FrameExtra, MiriInterpCx, MiriInterpCxExt, MiriMachine, MiriMemoryKind,
     PrimitiveLayouts, Provenance, ProvenanceExtra, PAGE_SIZE, STACK_ADDR, STACK_SIZE,
 };
 pub use crate::mono_hash_map::MonoHashMap;
 pub use crate::operator::EvalContextExt as _;
 pub use crate::range_map::RangeMap;
-pub use crate::stacked_borrows::{
-    CallId, EvalContextExt as _, Item, Permission, RetagFields, SbTag, Stack, Stacks,
-};
 pub use crate::tag_gc::{EvalContextExt as _, VisitTags};
 
 /// Insert rustc arguments at the beginning of the argument list that Miri wants to be
index edfef211dc675abcff79b316ed1f6335a18cf3df..e5b1eb2e4870696691a5f1672ea90f194665a865 100644 (file)
@@ -37,9 +37,9 @@
 pub const STACK_SIZE: u64 = 16 * PAGE_SIZE; // whatever
 
 /// Extra data stored with each stack frame
-pub struct FrameData<'tcx> {
+pub struct FrameExtra<'tcx> {
     /// Extra data for Stacked Borrows.
-    pub stacked_borrows: Option<stacked_borrows::FrameExtra>,
+    pub borrow_tracker: Option<borrow_tracker::FrameState>,
 
     /// If this is Some(), then this is a special "catch unwind" frame (the frame of `try_fn`
     /// called by `try`). When this frame is popped during unwinding a panic,
@@ -58,23 +58,23 @@ pub struct FrameData<'tcx> {
     pub is_user_relevant: bool,
 }
 
-impl<'tcx> std::fmt::Debug for FrameData<'tcx> {
+impl<'tcx> std::fmt::Debug for FrameExtra<'tcx> {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         // Omitting `timing`, it does not support `Debug`.
-        let FrameData { stacked_borrows, catch_unwind, timing: _, is_user_relevant: _ } = self;
+        let FrameExtra { borrow_tracker, catch_unwind, timing: _, is_user_relevant: _ } = self;
         f.debug_struct("FrameData")
-            .field("stacked_borrows", stacked_borrows)
+            .field("borrow_tracker", borrow_tracker)
             .field("catch_unwind", catch_unwind)
             .finish()
     }
 }
 
-impl VisitTags for FrameData<'_> {
-    fn visit_tags(&self, visit: &mut dyn FnMut(SbTag)) {
-        let FrameData { catch_unwind, stacked_borrows, timing: _, is_user_relevant: _ } = self;
+impl VisitTags for FrameExtra<'_> {
+    fn visit_tags(&self, visit: &mut dyn FnMut(BorTag)) {
+        let FrameExtra { catch_unwind, borrow_tracker, timing: _, is_user_relevant: _ } = self;
 
         catch_unwind.visit_tags(visit);
-        stacked_borrows.visit_tags(visit);
+        borrow_tracker.visit_tags(visit);
     }
 }
 
@@ -147,7 +147,7 @@ pub enum Provenance {
     Concrete {
         alloc_id: AllocId,
         /// Stacked Borrows tag.
-        sb: SbTag,
+        tag: BorTag,
     },
     Wildcard,
 }
@@ -173,7 +173,7 @@ fn hash<H: std::hash::Hasher>(&self, _state: &mut H) {
 /// The "extra" information a pointer has over a regular AllocId.
 #[derive(Copy, Clone, PartialEq)]
 pub enum ProvenanceExtra {
-    Concrete(SbTag),
+    Concrete(BorTag),
     Wildcard,
 }
 
@@ -188,7 +188,7 @@ pub enum ProvenanceExtra {
 impl fmt::Debug for Provenance {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         match self {
-            Provenance::Concrete { alloc_id, sb } => {
+            Provenance::Concrete { alloc_id, tag } => {
                 // Forward `alternate` flag to `alloc_id` printing.
                 if f.alternate() {
                     write!(f, "[{alloc_id:#?}]")?;
@@ -196,7 +196,7 @@ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
                     write!(f, "[{alloc_id:?}]")?;
                 }
                 // Print Stacked Borrows tag.
-                write!(f, "{sb:?}")?;
+                write!(f, "{tag:?}")?;
             }
             Provenance::Wildcard => {
                 write!(f, "[wildcard]")?;
@@ -221,9 +221,9 @@ fn join(left: Option<Self>, right: Option<Self>) -> Option<Self> {
         match (left, right) {
             // If both are the *same* concrete tag, that is the result.
             (
-                Some(Provenance::Concrete { alloc_id: left_alloc, sb: left_sb }),
-                Some(Provenance::Concrete { alloc_id: right_alloc, sb: right_sb }),
-            ) if left_alloc == right_alloc && left_sb == right_sb => left,
+                Some(Provenance::Concrete { alloc_id: left_alloc, tag: left_tag }),
+                Some(Provenance::Concrete { alloc_id: right_alloc, tag: right_tag }),
+            ) if left_alloc == right_alloc && left_tag == right_tag => left,
             // If one side is a wildcard, the best possible outcome is that it is equal to the other
             // one, and we use that.
             (Some(Provenance::Wildcard), o) | (o, Some(Provenance::Wildcard)) => o,
@@ -243,7 +243,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 }
 
 impl ProvenanceExtra {
-    pub fn and_then<T>(self, f: impl FnOnce(SbTag) -> Option<T>) -> Option<T> {
+    pub fn and_then<T>(self, f: impl FnOnce(BorTag) -> Option<T>) -> Option<T> {
         match self {
             ProvenanceExtra::Concrete(pid) => f(pid),
             ProvenanceExtra::Wildcard => None,
@@ -254,21 +254,21 @@ pub fn and_then<T>(self, f: impl FnOnce(SbTag) -> Option<T>) -> Option<T> {
 /// Extra per-allocation data
 #[derive(Debug, Clone)]
 pub struct AllocExtra {
-    /// Stacked Borrows state is only added if it is enabled.
-    pub stacked_borrows: Option<stacked_borrows::AllocExtra>,
+    /// Global state of the borrow tracker, if enabled.
+    pub borrow_tracker: Option<borrow_tracker::AllocState>,
     /// Data race detection via the use of a vector-clock,
     ///  this is only added if it is enabled.
-    pub data_race: Option<data_race::AllocExtra>,
+    pub data_race: Option<data_race::AllocState>,
     /// Weak memory emulation via the use of store buffers,
     ///  this is only added if it is enabled.
-    pub weak_memory: Option<weak_memory::AllocExtra>,
+    pub weak_memory: Option<weak_memory::AllocState>,
 }
 
 impl VisitTags for AllocExtra {
-    fn visit_tags(&self, visit: &mut dyn FnMut(SbTag)) {
-        let AllocExtra { stacked_borrows, data_race, weak_memory } = self;
+    fn visit_tags(&self, visit: &mut dyn FnMut(BorTag)) {
+        let AllocExtra { borrow_tracker, data_race, weak_memory } = self;
 
-        stacked_borrows.visit_tags(visit);
+        borrow_tracker.visit_tags(visit);
         data_race.visit_tags(visit);
         weak_memory.visit_tags(visit);
     }
@@ -350,8 +350,8 @@ pub struct MiriMachine<'mir, 'tcx> {
     // We carry a copy of the global `TyCtxt` for convenience, so methods taking just `&Evaluator` have `tcx` access.
     pub tcx: TyCtxt<'tcx>,
 
-    /// Stacked Borrows global data.
-    pub stacked_borrows: Option<stacked_borrows::GlobalState>,
+    /// Global data for borrow tracking.
+    pub borrow_tracker: Option<borrow_tracker::GlobalState>,
 
     /// Data race detector global data.
     pub data_race: Option<data_race::GlobalState>,
@@ -363,6 +363,9 @@ pub struct MiriMachine<'mir, 'tcx> {
     /// Miri does not expose env vars from the host to the emulated program.
     pub(crate) env_vars: EnvVars<'tcx>,
 
+    /// Return place of the main function.
+    pub(crate) main_fn_ret_place: Option<MemPlace<Provenance>>,
+
     /// Program arguments (`Option` because we can only initialize them after creating the ecx).
     /// These are *pointers* to argc/argv because macOS.
     /// We also need the full command line as one string because of Windows.
@@ -460,9 +463,9 @@ pub struct MiriMachine<'mir, 'tcx> {
     #[cfg(not(target_os = "linux"))]
     pub external_so_lib: Option<!>,
 
-    /// Run a garbage collector for SbTags every N basic blocks.
+    /// Run a garbage collector for BorTags every N basic blocks.
     pub(crate) gc_interval: u32,
-    /// The number of blocks that passed since the last SbTag GC pass.
+    /// The number of blocks that passed since the last BorTag GC pass.
     pub(crate) since_gc: u32,
     /// The number of CPUs to be reported by miri.
     pub(crate) num_cpus: u32,
@@ -477,21 +480,16 @@ pub(crate) fn new(config: &MiriConfig, layout_cx: LayoutCx<'tcx, TyCtxt<'tcx>>)
             measureme::Profiler::new(out).expect("Couldn't create `measureme` profiler")
         });
         let rng = StdRng::seed_from_u64(config.seed.unwrap_or(0));
-        let stacked_borrows = config.stacked_borrows.then(|| {
-            RefCell::new(stacked_borrows::GlobalStateInner::new(
-                config.tracked_pointer_tags.clone(),
-                config.tracked_call_ids.clone(),
-                config.retag_fields,
-            ))
-        });
+        let borrow_tracker = config.borrow_tracker.map(|bt| bt.instanciate_global_state(config));
         let data_race = config.data_race_detector.then(|| data_race::GlobalState::new(config));
         MiriMachine {
             tcx: layout_cx.tcx,
-            stacked_borrows,
+            borrow_tracker,
             data_race,
             intptrcast: RefCell::new(intptrcast::GlobalStateInner::new(config)),
             // `env_vars` depends on a full interpreter so we cannot properly initialize it yet.
             env_vars: EnvVars::default(),
+            main_fn_ret_place: None,
             argc: None,
             argv: None,
             cmd_line: None,
@@ -556,10 +554,11 @@ pub(crate) fn new(config: &MiriConfig, layout_cx: LayoutCx<'tcx, TyCtxt<'tcx>>)
     pub(crate) fn late_init(
         this: &mut MiriInterpCx<'mir, 'tcx>,
         config: &MiriConfig,
+        on_main_stack_empty: StackEmptyCallback<'mir, 'tcx>,
     ) -> InterpResult<'tcx> {
         EnvVars::init(this, config)?;
         MiriMachine::init_extern_statics(this)?;
-        ThreadManager::init(this);
+        ThreadManager::init(this, on_main_stack_empty);
         Ok(())
     }
 
@@ -651,18 +650,19 @@ pub(crate) fn is_local(&self, frame: &FrameInfo<'_>) -> bool {
 }
 
 impl VisitTags for MiriMachine<'_, '_> {
-    fn visit_tags(&self, visit: &mut dyn FnMut(SbTag)) {
+    fn visit_tags(&self, visit: &mut dyn FnMut(BorTag)) {
         #[rustfmt::skip]
         let MiriMachine {
             threads,
             tls,
             env_vars,
+            main_fn_ret_place,
             argc,
             argv,
             cmd_line,
             extern_statics,
             dir_handler,
-            stacked_borrows,
+            borrow_tracker,
             data_race,
             intptrcast,
             file_handler,
@@ -700,8 +700,9 @@ fn visit_tags(&self, visit: &mut dyn FnMut(SbTag)) {
         dir_handler.visit_tags(visit);
         file_handler.visit_tags(visit);
         data_race.visit_tags(visit);
-        stacked_borrows.visit_tags(visit);
+        borrow_tracker.visit_tags(visit);
         intptrcast.visit_tags(visit);
+        main_fn_ret_place.visit_tags(visit);
         argc.visit_tags(visit);
         argv.visit_tags(visit);
         cmd_line.visit_tags(visit);
@@ -735,7 +736,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for MiriMachine<'mir, 'tcx> {
     type MemoryKind = MiriMemoryKind;
     type ExtraFnVal = Dlsym;
 
-    type FrameExtra = FrameData<'tcx>;
+    type FrameExtra = FrameExtra<'tcx>;
     type AllocExtra = AllocExtra;
 
     type Provenance = Provenance;
@@ -900,25 +901,24 @@ fn adjust_allocation<'b>(
         }
 
         let alloc = alloc.into_owned();
-        let stacks = ecx.machine.stacked_borrows.as_ref().map(|stacked_borrows| {
-            Stacks::new_allocation(id, alloc.size(), stacked_borrows, kind, &ecx.machine)
-        });
+        let borrow_tracker = ecx
+            .machine
+            .borrow_tracker
+            .as_ref()
+            .map(|bt| bt.borrow_mut().new_allocation(id, alloc.size(), kind, &ecx.machine));
+
         let race_alloc = ecx.machine.data_race.as_ref().map(|data_race| {
-            data_race::AllocExtra::new_allocation(
+            data_race::AllocState::new_allocation(
                 data_race,
                 &ecx.machine.threads,
                 alloc.size(),
                 kind,
             )
         });
-        let buffer_alloc = ecx.machine.weak_memory.then(weak_memory::AllocExtra::new_allocation);
+        let buffer_alloc = ecx.machine.weak_memory.then(weak_memory::AllocState::new_allocation);
         let alloc: Allocation<Provenance, Self::AllocExtra> = alloc.adjust_from_tcx(
             &ecx.tcx,
-            AllocExtra {
-                stacked_borrows: stacks.map(RefCell::new),
-                data_race: race_alloc,
-                weak_memory: buffer_alloc,
-            },
+            AllocExtra { borrow_tracker, data_race: race_alloc, weak_memory: buffer_alloc },
             |ptr| ecx.global_base_pointer(ptr),
         )?;
         Ok(Cow::Owned(alloc))
@@ -942,14 +942,14 @@ fn adjust_alloc_base_pointer(
             }
         }
         let absolute_addr = intptrcast::GlobalStateInner::rel_ptr_to_addr(ecx, ptr);
-        let sb_tag = if let Some(stacked_borrows) = &ecx.machine.stacked_borrows {
-            stacked_borrows.borrow_mut().base_ptr_tag(ptr.provenance, &ecx.machine)
+        let tag = if let Some(borrow_tracker) = &ecx.machine.borrow_tracker {
+            borrow_tracker.borrow_mut().base_ptr_tag(ptr.provenance, &ecx.machine)
         } else {
             // Value does not matter, SB is disabled
-            SbTag::default()
+            BorTag::default()
         };
         Pointer::new(
-            Provenance::Concrete { alloc_id: ptr.provenance, sb: sb_tag },
+            Provenance::Concrete { alloc_id: ptr.provenance, tag },
             Size::from_bytes(absolute_addr),
         )
     }
@@ -967,8 +967,9 @@ fn expose_ptr(
         ptr: Pointer<Self::Provenance>,
     ) -> InterpResult<'tcx> {
         match ptr.provenance {
-            Provenance::Concrete { alloc_id, sb } =>
-                intptrcast::GlobalStateInner::expose_ptr(ecx, alloc_id, sb),
+            Provenance::Concrete { alloc_id, tag } => {
+                intptrcast::GlobalStateInner::expose_ptr(ecx, alloc_id, tag)
+            }
             Provenance::Wildcard => {
                 // No need to do anything for wildcard pointers as
                 // their provenances have already been previously exposed.
@@ -986,11 +987,11 @@ fn ptr_get_alloc(
         let rel = intptrcast::GlobalStateInner::abs_ptr_to_rel(ecx, ptr);
 
         rel.map(|(alloc_id, size)| {
-            let sb = match ptr.provenance {
-                Provenance::Concrete { sb, .. } => ProvenanceExtra::Concrete(sb),
+            let tag = match ptr.provenance {
+                Provenance::Concrete { tag, .. } => ProvenanceExtra::Concrete(tag),
                 Provenance::Wildcard => ProvenanceExtra::Wildcard,
             };
-            (alloc_id, size, sb)
+            (alloc_id, size, tag)
         })
     }
 
@@ -1005,10 +1006,8 @@ fn before_memory_read(
         if let Some(data_race) = &alloc_extra.data_race {
             data_race.read(alloc_id, range, machine)?;
         }
-        if let Some(stacked_borrows) = &alloc_extra.stacked_borrows {
-            stacked_borrows
-                .borrow_mut()
-                .before_memory_read(alloc_id, prov_extra, range, machine)?;
+        if let Some(borrow_tracker) = &alloc_extra.borrow_tracker {
+            borrow_tracker.before_memory_read(alloc_id, prov_extra, range, machine)?;
         }
         if let Some(weak_memory) = &alloc_extra.weak_memory {
             weak_memory.memory_accessed(range, machine.data_race.as_ref().unwrap());
@@ -1027,8 +1026,8 @@ fn before_memory_write(
         if let Some(data_race) = &mut alloc_extra.data_race {
             data_race.write(alloc_id, range, machine)?;
         }
-        if let Some(stacked_borrows) = &mut alloc_extra.stacked_borrows {
-            stacked_borrows.get_mut().before_memory_write(alloc_id, prov_extra, range, machine)?;
+        if let Some(borrow_tracker) = &mut alloc_extra.borrow_tracker {
+            borrow_tracker.before_memory_write(alloc_id, prov_extra, range, machine)?;
         }
         if let Some(weak_memory) = &alloc_extra.weak_memory {
             weak_memory.memory_accessed(range, machine.data_race.as_ref().unwrap());
@@ -1050,32 +1049,42 @@ fn before_memory_deallocation(
         if let Some(data_race) = &mut alloc_extra.data_race {
             data_race.deallocate(alloc_id, range, machine)?;
         }
-        if let Some(stacked_borrows) = &mut alloc_extra.stacked_borrows {
-            stacked_borrows.get_mut().before_memory_deallocation(
-                alloc_id,
-                prove_extra,
-                range,
-                machine,
-            )
+        if let Some(borrow_tracker) = &mut alloc_extra.borrow_tracker {
+            borrow_tracker.before_memory_deallocation(alloc_id, prove_extra, range, machine)?;
+        }
+        Ok(())
+    }
+
+    #[inline(always)]
+    fn retag_ptr_value(
+        ecx: &mut InterpCx<'mir, 'tcx, Self>,
+        kind: mir::RetagKind,
+        val: &ImmTy<'tcx, Provenance>,
+    ) -> InterpResult<'tcx, ImmTy<'tcx, Provenance>> {
+        if ecx.machine.borrow_tracker.is_some() {
+            ecx.retag_ptr_value(kind, val)
         } else {
-            Ok(())
+            Ok(val.clone())
         }
     }
 
     #[inline(always)]
-    fn retag(
+    fn retag_place_contents(
         ecx: &mut InterpCx<'mir, 'tcx, Self>,
         kind: mir::RetagKind,
         place: &PlaceTy<'tcx, Provenance>,
     ) -> InterpResult<'tcx> {
-        if ecx.machine.stacked_borrows.is_some() { ecx.retag(kind, place) } else { Ok(()) }
+        if ecx.machine.borrow_tracker.is_some() {
+            ecx.retag_place_contents(kind, place)?;
+        }
+        Ok(())
     }
 
     #[inline(always)]
     fn init_frame_extra(
         ecx: &mut InterpCx<'mir, 'tcx, Self>,
         frame: Frame<'mir, 'tcx, Provenance>,
-    ) -> InterpResult<'tcx, Frame<'mir, 'tcx, Provenance, FrameData<'tcx>>> {
+    ) -> InterpResult<'tcx, Frame<'mir, 'tcx, Provenance, FrameExtra<'tcx>>> {
         // Start recording our event before doing anything else
         let timing = if let Some(profiler) = ecx.machine.profiler.as_ref() {
             let fn_name = frame.instance.to_string();
@@ -1091,10 +1100,10 @@ fn init_frame_extra(
             None
         };
 
-        let stacked_borrows = ecx.machine.stacked_borrows.as_ref();
+        let borrow_tracker = ecx.machine.borrow_tracker.as_ref();
 
-        let extra = FrameData {
-            stacked_borrows: stacked_borrows.map(|sb| sb.borrow_mut().new_frame(&ecx.machine)),
+        let extra = FrameExtra {
+            borrow_tracker: borrow_tracker.map(|bt| bt.borrow_mut().new_frame(&ecx.machine)),
             catch_unwind: None,
             timing,
             is_user_relevant: ecx.machine.is_user_relevant(&frame),
@@ -1127,7 +1136,7 @@ fn before_terminator(ecx: &mut InterpCx<'mir, 'tcx, Self>) -> InterpResult<'tcx>
             }
         }
 
-        // Search for SbTags to find all live pointers, then remove all other tags from borrow
+        // Search for BorTags to find all live pointers, then remove all other tags from borrow
         // stacks.
         // When debug assertions are enabled, run the GC as often as possible so that any cases
         // where it mistakenly removes an important tag become visible.
@@ -1153,14 +1162,16 @@ fn after_stack_push(ecx: &mut InterpCx<'mir, 'tcx, Self>) -> InterpResult<'tcx>
             let stack_len = ecx.active_thread_stack().len();
             ecx.active_thread_mut().set_top_user_relevant_frame(stack_len - 1);
         }
-
-        if ecx.machine.stacked_borrows.is_some() { ecx.retag_return_place() } else { Ok(()) }
+        if ecx.machine.borrow_tracker.is_some() {
+            ecx.retag_return_place()?;
+        }
+        Ok(())
     }
 
     #[inline(always)]
     fn after_stack_pop(
         ecx: &mut InterpCx<'mir, 'tcx, Self>,
-        mut frame: Frame<'mir, 'tcx, Provenance, FrameData<'tcx>>,
+        mut frame: Frame<'mir, 'tcx, Provenance, FrameExtra<'tcx>>,
         unwinding: bool,
     ) -> InterpResult<'tcx, StackPopJump> {
         if frame.extra.is_user_relevant {
@@ -1171,8 +1182,8 @@ fn after_stack_pop(
             ecx.active_thread_mut().recompute_top_user_relevant_frame();
         }
         let timing = frame.extra.timing.take();
-        if let Some(stacked_borrows) = &ecx.machine.stacked_borrows {
-            stacked_borrows.borrow_mut().end_call(&frame.extra);
+        if let Some(borrow_tracker) = &ecx.machine.borrow_tracker {
+            borrow_tracker.borrow_mut().end_call(&frame.extra);
         }
         let res = ecx.handle_stack_pop_unwind(frame.extra, unwinding);
         if let Some(profiler) = ecx.machine.profiler.as_ref() {
index bf6c1f8756290528017b55b3204fc546f99479d1..80fb4ff2fe9802e051d61389f3f90c67978bddce 100644 (file)
@@ -37,7 +37,7 @@ pub struct EnvVars<'tcx> {
 }
 
 impl VisitTags for EnvVars<'_> {
-    fn visit_tags(&self, visit: &mut dyn FnMut(SbTag)) {
+    fn visit_tags(&self, visit: &mut dyn FnMut(BorTag)) {
         let EnvVars { map, environ } = self;
 
         environ.visit_tags(visit);
index 058f730833bb41983685d7cadc644ae6f4e7c1ba..8370e02b588afb7f5d19da5052cde4d5a2994cb3 100644 (file)
@@ -286,7 +286,7 @@ fn emulate_foreign_item(
                         let [code] = this.check_shim(abi, exp_abi, link_name, args)?;
                         // it's really u32 for ExitProcess, but we have to put it into the `Exit` variant anyway
                         let code = this.read_scalar(code)?.to_i32()?;
-                        throw_machine_stop!(TerminationInfo::Exit(code.into()));
+                        throw_machine_stop!(TerminationInfo::Exit { code: code.into(), leak_check: false });
                     }
                     "abort" => {
                         let [] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
@@ -299,8 +299,7 @@ fn emulate_foreign_item(
                             return Ok(Some(body));
                         }
                         this.handle_unsupported(format!(
-                            "can't call (diverging) foreign function: {}",
-                            link_name
+                            "can't call (diverging) foreign function: {link_name}"
                         ))?;
                         return Ok(None);
                     }
index 698e025961da83c174affcb58a6572a4a325e8d2..db3e42facadd03958c1d8725b7c44be4645692db 100644 (file)
@@ -36,7 +36,7 @@ pub struct CatchUnwindData<'tcx> {
 }
 
 impl VisitTags for CatchUnwindData<'_> {
-    fn visit_tags(&self, visit: &mut dyn FnMut(SbTag)) {
+    fn visit_tags(&self, visit: &mut dyn FnMut(BorTag)) {
         let CatchUnwindData { catch_fn, data, dest, ret: _ } = self;
         catch_fn.visit_tags(visit);
         data.visit_tags(visit);
@@ -125,7 +125,7 @@ fn handle_try(
 
     fn handle_stack_pop_unwind(
         &mut self,
-        mut extra: FrameData<'tcx>,
+        mut extra: FrameExtra<'tcx>,
         unwinding: bool,
     ) -> InterpResult<'tcx, StackPopJump> {
         let this = self.eval_context_mut();
index bc0b71fbc2096438dce1d725341353ef06d516ad..d263aab351b12e07591210cc85ede4bc60c461c0 100644 (file)
@@ -278,7 +278,7 @@ struct UnblockCallback {
 }
 
 impl VisitTags for UnblockCallback {
-    fn visit_tags(&self, _visit: &mut dyn FnMut(SbTag)) {}
+    fn visit_tags(&self, _visit: &mut dyn FnMut(BorTag)) {}
 }
 
 impl<'mir, 'tcx: 'mir> MachineCallback<'mir, 'tcx> for UnblockCallback {
index 5fda8bd7b7de9a2c00a891e012914e9cca914f79..54fdf2872ab4d3967c594fba3d30def27840b96f 100644 (file)
@@ -1,12 +1,11 @@
 //! Implement thread-local storage.
 
 use std::collections::btree_map::Entry as BTreeEntry;
-use std::collections::hash_map::Entry as HashMapEntry;
 use std::collections::BTreeMap;
+use std::task::Poll;
 
 use log::trace;
 
-use rustc_data_structures::fx::FxHashMap;
 use rustc_middle::ty;
 use rustc_target::abi::{HasDataLayout, Size};
 use rustc_target::spec::abi::Abi;
@@ -23,12 +22,12 @@ pub struct TlsEntry<'tcx> {
     dtor: Option<ty::Instance<'tcx>>,
 }
 
-#[derive(Clone, Debug)]
-struct RunningDtorsState {
+#[derive(Default, Debug)]
+struct RunningDtorState {
     /// The last TlsKey used to retrieve a TLS destructor. `None` means that we
     /// have not tried to retrieve a TLS destructor yet or that we already tried
     /// all keys.
-    last_dtor_key: Option<TlsKey>,
+    last_key: Option<TlsKey>,
 }
 
 #[derive(Debug)]
@@ -42,11 +41,6 @@ pub struct TlsData<'tcx> {
     /// A single per thread destructor of the thread local storage (that's how
     /// things work on macOS) with a data argument.
     macos_thread_dtors: BTreeMap<ThreadId, (ty::Instance<'tcx>, Scalar<Provenance>)>,
-
-    /// State for currently running TLS dtors. If this map contains a key for a
-    /// specific thread, it means that we are in the "destruct" phase, during
-    /// which some operations are UB.
-    dtors_running: FxHashMap<ThreadId, RunningDtorsState>,
 }
 
 impl<'tcx> Default for TlsData<'tcx> {
@@ -55,7 +49,6 @@ fn default() -> Self {
             next_key: 1, // start with 1 as we must not use 0 on Windows
             keys: Default::default(),
             macos_thread_dtors: Default::default(),
-            dtors_running: Default::default(),
         }
     }
 }
@@ -143,12 +136,6 @@ pub fn set_macos_thread_dtor(
         dtor: ty::Instance<'tcx>,
         data: Scalar<Provenance>,
     ) -> InterpResult<'tcx> {
-        if self.dtors_running.contains_key(&thread) {
-            // UB, according to libstd docs.
-            throw_ub_format!(
-                "setting thread's local storage destructor while destructors are already running"
-            );
-        }
         if self.macos_thread_dtors.insert(thread, (dtor, data)).is_some() {
             throw_unsup_format!(
                 "setting more than one thread local storage destructor for the same thread is not supported"
@@ -211,21 +198,6 @@ fn fetch_tls_dtor(
         None
     }
 
-    /// Set that dtors are running for `thread`. It is guaranteed not to change
-    /// the existing values stored in `dtors_running` for this thread. Returns
-    /// `true` if dtors for `thread` are already running.
-    fn set_dtors_running_for_thread(&mut self, thread: ThreadId) -> bool {
-        match self.dtors_running.entry(thread) {
-            HashMapEntry::Occupied(_) => true,
-            HashMapEntry::Vacant(entry) => {
-                // We cannot just do `self.dtors_running.insert` because that
-                // would overwrite `last_dtor_key` with `None`.
-                entry.insert(RunningDtorsState { last_dtor_key: None });
-                false
-            }
-        }
-    }
-
     /// Delete all TLS entries for the given thread. This function should be
     /// called after all TLS destructors have already finished.
     fn delete_all_thread_tls(&mut self, thread_id: ThreadId) {
@@ -236,8 +208,8 @@ fn delete_all_thread_tls(&mut self, thread_id: ThreadId) {
 }
 
 impl VisitTags for TlsData<'_> {
-    fn visit_tags(&self, visit: &mut dyn FnMut(SbTag)) {
-        let TlsData { keys, macos_thread_dtors, next_key: _, dtors_running: _ } = self;
+    fn visit_tags(&self, visit: &mut dyn FnMut(BorTag)) {
+        let TlsData { keys, macos_thread_dtors, next_key: _ } = self;
 
         for scalar in keys.values().flat_map(|v| v.data.values()) {
             scalar.visit_tags(visit);
@@ -248,13 +220,77 @@ fn visit_tags(&self, visit: &mut dyn FnMut(SbTag)) {
     }
 }
 
+#[derive(Debug, Default)]
+pub struct TlsDtorsState(TlsDtorsStatePriv);
+
+#[derive(Debug, Default)]
+enum TlsDtorsStatePriv {
+    #[default]
+    Init,
+    PthreadDtors(RunningDtorState),
+    Done,
+}
+
+impl TlsDtorsState {
+    pub fn on_stack_empty<'tcx>(
+        &mut self,
+        this: &mut MiriInterpCx<'_, 'tcx>,
+    ) -> InterpResult<'tcx, Poll<()>> {
+        use TlsDtorsStatePriv::*;
+        match &mut self.0 {
+            Init => {
+                match this.tcx.sess.target.os.as_ref() {
+                    "linux" | "freebsd" | "android" => {
+                        // Run the pthread dtors.
+                        self.0 = PthreadDtors(Default::default());
+                    }
+                    "macos" => {
+                        // The macOS thread wide destructor runs "before any TLS slots get
+                        // freed", so do that first.
+                        this.schedule_macos_tls_dtor()?;
+                        // When the stack is empty again, go on with the pthread dtors.
+                        self.0 = PthreadDtors(Default::default());
+                    }
+                    "windows" => {
+                        // Run the special magic hook.
+                        this.schedule_windows_tls_dtors()?;
+                        // And move to the final state.
+                        self.0 = Done;
+                    }
+                    "wasi" | "none" => {
+                        // No OS, no TLS dtors.
+                        // FIXME: should we do something on wasi?
+                        self.0 = Done;
+                    }
+                    os => {
+                        throw_unsup_format!(
+                            "the TLS machinery does not know how to handle OS `{os}`"
+                        );
+                    }
+                }
+            }
+            PthreadDtors(state) => {
+                match this.schedule_next_pthread_tls_dtor(state)? {
+                    Poll::Pending => {} // just keep going
+                    Poll::Ready(()) => self.0 = Done,
+                }
+            }
+            Done => {
+                this.machine.tls.delete_all_thread_tls(this.get_active_thread());
+                return Ok(Poll::Ready(()));
+            }
+        }
+
+        Ok(Poll::Pending)
+    }
+}
+
 impl<'mir, 'tcx: 'mir> EvalContextPrivExt<'mir, 'tcx> for crate::MiriInterpCx<'mir, 'tcx> {}
 trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
     /// Schedule TLS destructors for Windows.
     /// On windows, TLS destructors are managed by std.
     fn schedule_windows_tls_dtors(&mut self) -> InterpResult<'tcx> {
         let this = self.eval_context_mut();
-        let active_thread = this.get_active_thread();
 
         // Windows has a special magic linker section that is run on certain events.
         // Instead of searching for that section and supporting arbitrary hooks in there
@@ -284,16 +320,12 @@ fn schedule_windows_tls_dtors(&mut self) -> InterpResult<'tcx> {
             None,
             StackPopCleanup::Root { cleanup: true },
         )?;
-
-        this.enable_thread(active_thread);
         Ok(())
     }
 
     /// Schedule the MacOS thread destructor of the thread local storage to be
-    /// executed. Returns `true` if scheduled.
-    ///
-    /// Note: It is safe to call this function also on other Unixes.
-    fn schedule_macos_tls_dtor(&mut self) -> InterpResult<'tcx, bool> {
+    /// executed.
+    fn schedule_macos_tls_dtor(&mut self) -> InterpResult<'tcx> {
         let this = self.eval_context_mut();
         let thread_id = this.get_active_thread();
         if let Some((instance, data)) = this.machine.tls.macos_thread_dtors.remove(&thread_id) {
@@ -306,35 +338,27 @@ fn schedule_macos_tls_dtor(&mut self) -> InterpResult<'tcx, bool> {
                 None,
                 StackPopCleanup::Root { cleanup: true },
             )?;
-
-            // Enable the thread so that it steps through the destructor which
-            // we just scheduled. Since we deleted the destructor, it is
-            // guaranteed that we will schedule it again. The `dtors_running`
-            // flag will prevent the code from adding the destructor again.
-            this.enable_thread(thread_id);
-            Ok(true)
-        } else {
-            Ok(false)
         }
+        Ok(())
     }
 
     /// Schedule a pthread TLS destructor. Returns `true` if found
     /// a destructor to schedule, and `false` otherwise.
-    fn schedule_next_pthread_tls_dtor(&mut self) -> InterpResult<'tcx, bool> {
+    fn schedule_next_pthread_tls_dtor(
+        &mut self,
+        state: &mut RunningDtorState,
+    ) -> InterpResult<'tcx, Poll<()>> {
         let this = self.eval_context_mut();
         let active_thread = this.get_active_thread();
 
-        assert!(this.has_terminated(active_thread), "running TLS dtors for non-terminated thread");
         // Fetch next dtor after `key`.
-        let last_key = this.machine.tls.dtors_running[&active_thread].last_dtor_key;
-        let dtor = match this.machine.tls.fetch_tls_dtor(last_key, active_thread) {
+        let dtor = match this.machine.tls.fetch_tls_dtor(state.last_key, active_thread) {
             dtor @ Some(_) => dtor,
             // We ran each dtor once, start over from the beginning.
             None => this.machine.tls.fetch_tls_dtor(None, active_thread),
         };
         if let Some((instance, ptr, key)) = dtor {
-            this.machine.tls.dtors_running.get_mut(&active_thread).unwrap().last_dtor_key =
-                Some(key);
+            state.last_key = Some(key);
             trace!("Running TLS dtor {:?} on {:?} at {:?}", instance, ptr, active_thread);
             assert!(
                 !ptr.to_machine_usize(this).unwrap() != 0,
@@ -349,64 +373,9 @@ fn schedule_next_pthread_tls_dtor(&mut self) -> InterpResult<'tcx, bool> {
                 StackPopCleanup::Root { cleanup: true },
             )?;
 
-            this.enable_thread(active_thread);
-            return Ok(true);
-        }
-        this.machine.tls.dtors_running.get_mut(&active_thread).unwrap().last_dtor_key = None;
-
-        Ok(false)
-    }
-}
-
-impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriInterpCx<'mir, 'tcx> {}
-pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
-    /// Schedule an active thread's TLS destructor to run on the active thread.
-    /// Note that this function does not run the destructors itself, it just
-    /// schedules them one by one each time it is called and reenables the
-    /// thread so that it can be executed normally by the main execution loop.
-    ///
-    /// Note: we consistently run TLS destructors for all threads, including the
-    /// main thread. However, it is not clear that we should run the TLS
-    /// destructors for the main thread. See issue:
-    /// <https://github.com/rust-lang/rust/issues/28129>.
-    fn schedule_next_tls_dtor_for_active_thread(&mut self) -> InterpResult<'tcx> {
-        let this = self.eval_context_mut();
-        let active_thread = this.get_active_thread();
-        trace!("schedule_next_tls_dtor_for_active_thread on thread {:?}", active_thread);
-
-        if !this.machine.tls.set_dtors_running_for_thread(active_thread) {
-            // This is the first time we got asked to schedule a destructor. The
-            // Windows schedule destructor function must be called exactly once,
-            // this is why it is in this block.
-            if this.tcx.sess.target.os == "windows" {
-                // On Windows, we signal that the thread quit by starting the
-                // relevant function, reenabling the thread, and going back to
-                // the scheduler.
-                this.schedule_windows_tls_dtors()?;
-                return Ok(());
-            }
+            return Ok(Poll::Pending);
         }
-        // The remaining dtors make some progress each time around the scheduler loop,
-        // until they return `false` to indicate that they are done.
-
-        // The macOS thread wide destructor runs "before any TLS slots get
-        // freed", so do that first.
-        if this.schedule_macos_tls_dtor()? {
-            // We have scheduled a MacOS dtor to run on the thread. Execute it
-            // to completion and come back here. Scheduling a destructor
-            // destroys it, so we will not enter this branch again.
-            return Ok(());
-        }
-        if this.schedule_next_pthread_tls_dtor()? {
-            // We have scheduled a pthread destructor and removed it from the
-            // destructors list. Run it to completion and come back here.
-            return Ok(());
-        }
-
-        // All dtors done!
-        this.machine.tls.delete_all_thread_tls(active_thread);
-        this.thread_terminated()?;
 
-        Ok(())
+        Ok(Poll::Ready(()))
     }
 }
index e048d53a17e0d498630b698711e830ec60b12ac5..988627db5611c283c0ee35c8b5e77fe6a97f18e7 100644 (file)
@@ -278,7 +278,7 @@ pub struct FileHandler {
 }
 
 impl VisitTags for FileHandler {
-    fn visit_tags(&self, _visit: &mut dyn FnMut(SbTag)) {
+    fn visit_tags(&self, _visit: &mut dyn FnMut(BorTag)) {
         // All our FileDescriptor do not have any tags.
     }
 }
@@ -490,7 +490,7 @@ fn default() -> DirHandler {
 }
 
 impl VisitTags for DirHandler {
-    fn visit_tags(&self, visit: &mut dyn FnMut(SbTag)) {
+    fn visit_tags(&self, visit: &mut dyn FnMut(BorTag)) {
         let DirHandler { streams, next_id: _ } = self;
 
         for dir in streams.values() {
index 292b9d2e7a17626a5641bfbb1d3d5bc7c7d6065d..343232c4bbb2913a247d6c13c622806660ecbb84 100644 (file)
@@ -183,7 +183,7 @@ struct Callback<'tcx> {
                     }
 
                     impl<'tcx> VisitTags for Callback<'tcx> {
-                        fn visit_tags(&self, visit: &mut dyn FnMut(SbTag)) {
+                        fn visit_tags(&self, visit: &mut dyn FnMut(BorTag)) {
                             let Callback { thread: _, addr_usize: _, dest } = self;
                             dest.visit_tags(visit);
                         }
index e0afb500cb18a99cb4309ec40dbd08f91975ee94..f9b5774f0090e05ece1d5e2703386a2452091fae 100644 (file)
@@ -747,7 +747,7 @@ struct Callback<'tcx> {
         }
 
         impl<'tcx> VisitTags for Callback<'tcx> {
-            fn visit_tags(&self, visit: &mut dyn FnMut(SbTag)) {
+            fn visit_tags(&self, visit: &mut dyn FnMut(BorTag)) {
                 let Callback { active_thread: _, mutex_id: _, id: _, dest } = self;
                 dest.visit_tags(visit);
             }
index b43682710bbe5c4adfba87955bb184f259348845..5b9dc90f0f0060c63524e4297e83aec4d8301532 100644 (file)
@@ -19,7 +19,7 @@ fn pthread_create(
 
         let func_arg = this.read_immediate(arg)?;
 
-        this.start_thread(
+        this.start_regular_thread(
             Some(thread_info_place),
             start_routine,
             Abi::C { unwind: false },
index 8f414d98dba5f70a979aa132a0caac8bbdd979c5..6b043c6d2c9e1c723d2d242d1ff12e896f3a61c7 100644 (file)
@@ -182,7 +182,7 @@ struct Callback<'tcx> {
                 }
 
                 impl<'tcx> VisitTags for Callback<'tcx> {
-                    fn visit_tags(&self, visit: &mut dyn FnMut(SbTag)) {
+                    fn visit_tags(&self, visit: &mut dyn FnMut(BorTag)) {
                         let Callback { init_once_id: _, pending_place } = self;
                         pending_place.visit_tags(visit);
                     }
@@ -315,7 +315,7 @@ struct Callback<'tcx> {
                 }
 
                 impl<'tcx> VisitTags for Callback<'tcx> {
-                    fn visit_tags(&self, visit: &mut dyn FnMut(SbTag)) {
+                    fn visit_tags(&self, visit: &mut dyn FnMut(BorTag)) {
                         let Callback { thread: _, addr: _, dest } = self;
                         dest.visit_tags(visit);
                     }
@@ -419,7 +419,7 @@ struct Callback<'tcx> {
             }
 
             impl<'tcx> VisitTags for Callback<'tcx> {
-                fn visit_tags(&self, visit: &mut dyn FnMut(SbTag)) {
+                fn visit_tags(&self, visit: &mut dyn FnMut(BorTag)) {
                     let Callback { thread: _, condvar_id: _, lock_id: _, mode: _, dest } = self;
                     dest.visit_tags(visit);
                 }
index 5ed0cb92f9e347acbb78a2259c392d131739c0d8..25a5194caa096540d997df4c13dfe33c42ca9464 100644 (file)
@@ -46,7 +46,7 @@ fn CreateThread(
             throw_unsup_format!("non-null `lpThreadAttributes` in `CreateThread`")
         }
 
-        this.start_thread(
+        this.start_regular_thread(
             thread,
             start_routine,
             Abi::System { unwind: false },
diff --git a/src/tools/miri/src/stacked_borrows/diagnostics.rs b/src/tools/miri/src/stacked_borrows/diagnostics.rs
deleted file mode 100644 (file)
index 9970b79..0000000
+++ /dev/null
@@ -1,506 +0,0 @@
-use smallvec::SmallVec;
-use std::fmt;
-
-use rustc_middle::mir::interpret::{alloc_range, AllocId, AllocRange};
-use rustc_span::{Span, SpanData};
-use rustc_target::abi::Size;
-
-use crate::stacked_borrows::{err_sb_ub, AccessKind, GlobalStateInner, Permission, ProtectorKind};
-use crate::*;
-
-use rustc_middle::mir::interpret::InterpError;
-
-#[derive(Clone, Debug)]
-pub struct AllocHistory {
-    id: AllocId,
-    base: (Item, Span),
-    creations: smallvec::SmallVec<[Creation; 1]>,
-    invalidations: smallvec::SmallVec<[Invalidation; 1]>,
-    protectors: smallvec::SmallVec<[Protection; 1]>,
-}
-
-#[derive(Clone, Debug)]
-struct Creation {
-    retag: RetagOp,
-    span: Span,
-}
-
-impl Creation {
-    fn generate_diagnostic(&self) -> (String, SpanData) {
-        let tag = self.retag.new_tag;
-        if let Some(perm) = self.retag.permission {
-            (
-                format!(
-                    "{tag:?} was created by a {:?} retag at offsets {:?}",
-                    perm, self.retag.range,
-                ),
-                self.span.data(),
-            )
-        } else {
-            assert!(self.retag.range.size == Size::ZERO);
-            (
-                format!(
-                    "{tag:?} would have been created here, but this is a zero-size retag ({:?}) so the tag in question does not exist anywhere",
-                    self.retag.range,
-                ),
-                self.span.data(),
-            )
-        }
-    }
-}
-
-#[derive(Clone, Debug)]
-struct Invalidation {
-    tag: SbTag,
-    range: AllocRange,
-    span: Span,
-    cause: InvalidationCause,
-}
-
-#[derive(Clone, Debug)]
-enum InvalidationCause {
-    Access(AccessKind),
-    Retag(Permission, RetagCause),
-}
-
-impl Invalidation {
-    fn generate_diagnostic(&self) -> (String, SpanData) {
-        let message = if let InvalidationCause::Retag(_, RetagCause::FnEntry) = self.cause {
-            // For a FnEntry retag, our Span points at the caller.
-            // See `DiagnosticCx::log_invalidation`.
-            format!(
-                "{:?} was later invalidated at offsets {:?} by a {} inside this call",
-                self.tag, self.range, self.cause
-            )
-        } else {
-            format!(
-                "{:?} was later invalidated at offsets {:?} by a {}",
-                self.tag, self.range, self.cause
-            )
-        };
-        (message, self.span.data())
-    }
-}
-
-impl fmt::Display for InvalidationCause {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        match self {
-            InvalidationCause::Access(kind) => write!(f, "{kind}"),
-            InvalidationCause::Retag(perm, kind) =>
-                if *kind == RetagCause::FnEntry {
-                    write!(f, "{perm:?} FnEntry retag")
-                } else {
-                    write!(f, "{perm:?} retag")
-                },
-        }
-    }
-}
-
-#[derive(Clone, Debug)]
-struct Protection {
-    tag: SbTag,
-    span: Span,
-}
-
-#[derive(Clone)]
-pub struct TagHistory {
-    pub created: (String, SpanData),
-    pub invalidated: Option<(String, SpanData)>,
-    pub protected: Option<(String, SpanData)>,
-}
-
-pub struct DiagnosticCxBuilder<'ecx, 'mir, 'tcx> {
-    operation: Operation,
-    machine: &'ecx MiriMachine<'mir, 'tcx>,
-}
-
-pub struct DiagnosticCx<'history, 'ecx, 'mir, 'tcx> {
-    operation: Operation,
-    machine: &'ecx MiriMachine<'mir, 'tcx>,
-    history: &'history mut AllocHistory,
-    offset: Size,
-}
-
-impl<'ecx, 'mir, 'tcx> DiagnosticCxBuilder<'ecx, 'mir, 'tcx> {
-    pub fn build<'history>(
-        self,
-        history: &'history mut AllocHistory,
-        offset: Size,
-    ) -> DiagnosticCx<'history, 'ecx, 'mir, 'tcx> {
-        DiagnosticCx { operation: self.operation, machine: self.machine, history, offset }
-    }
-
-    pub fn retag(
-        machine: &'ecx MiriMachine<'mir, 'tcx>,
-        cause: RetagCause,
-        new_tag: SbTag,
-        orig_tag: ProvenanceExtra,
-        range: AllocRange,
-    ) -> Self {
-        let operation =
-            Operation::Retag(RetagOp { cause, new_tag, orig_tag, range, permission: None });
-
-        DiagnosticCxBuilder { machine, operation }
-    }
-
-    pub fn read(
-        machine: &'ecx MiriMachine<'mir, 'tcx>,
-        tag: ProvenanceExtra,
-        range: AllocRange,
-    ) -> Self {
-        let operation = Operation::Access(AccessOp { kind: AccessKind::Read, tag, range });
-        DiagnosticCxBuilder { machine, operation }
-    }
-
-    pub fn write(
-        machine: &'ecx MiriMachine<'mir, 'tcx>,
-        tag: ProvenanceExtra,
-        range: AllocRange,
-    ) -> Self {
-        let operation = Operation::Access(AccessOp { kind: AccessKind::Write, tag, range });
-        DiagnosticCxBuilder { machine, operation }
-    }
-
-    pub fn dealloc(machine: &'ecx MiriMachine<'mir, 'tcx>, tag: ProvenanceExtra) -> Self {
-        let operation = Operation::Dealloc(DeallocOp { tag });
-        DiagnosticCxBuilder { machine, operation }
-    }
-}
-
-impl<'history, 'ecx, 'mir, 'tcx> DiagnosticCx<'history, 'ecx, 'mir, 'tcx> {
-    pub fn unbuild(self) -> DiagnosticCxBuilder<'ecx, 'mir, 'tcx> {
-        DiagnosticCxBuilder { machine: self.machine, operation: self.operation }
-    }
-}
-
-#[derive(Debug, Clone)]
-enum Operation {
-    Retag(RetagOp),
-    Access(AccessOp),
-    Dealloc(DeallocOp),
-}
-
-#[derive(Debug, Clone)]
-struct RetagOp {
-    cause: RetagCause,
-    new_tag: SbTag,
-    orig_tag: ProvenanceExtra,
-    range: AllocRange,
-    permission: Option<Permission>,
-}
-
-#[derive(Debug, Clone, Copy, PartialEq)]
-pub enum RetagCause {
-    Normal,
-    FnReturn,
-    FnEntry,
-    TwoPhase,
-}
-
-#[derive(Debug, Clone)]
-struct AccessOp {
-    kind: AccessKind,
-    tag: ProvenanceExtra,
-    range: AllocRange,
-}
-
-#[derive(Debug, Clone)]
-struct DeallocOp {
-    tag: ProvenanceExtra,
-}
-
-impl AllocHistory {
-    pub fn new(id: AllocId, item: Item, machine: &MiriMachine<'_, '_>) -> Self {
-        Self {
-            id,
-            base: (item, machine.current_span()),
-            creations: SmallVec::new(),
-            invalidations: SmallVec::new(),
-            protectors: SmallVec::new(),
-        }
-    }
-}
-
-impl<'history, 'ecx, 'mir, 'tcx> DiagnosticCx<'history, 'ecx, 'mir, 'tcx> {
-    pub fn start_grant(&mut self, perm: Permission) {
-        let Operation::Retag(op) = &mut self.operation else {
-            unreachable!("start_grant must only be called during a retag, this is: {:?}", self.operation)
-        };
-        op.permission = Some(perm);
-
-        let last_creation = &mut self.history.creations.last_mut().unwrap();
-        match last_creation.retag.permission {
-            None => {
-                last_creation.retag.permission = Some(perm);
-            }
-            Some(previous) =>
-                if previous != perm {
-                    // 'Split up' the creation event.
-                    let previous_range = last_creation.retag.range;
-                    last_creation.retag.range = alloc_range(previous_range.start, self.offset);
-                    let mut new_event = last_creation.clone();
-                    new_event.retag.range = alloc_range(self.offset, previous_range.end());
-                    new_event.retag.permission = Some(perm);
-                    self.history.creations.push(new_event);
-                },
-        }
-    }
-
-    pub fn log_creation(&mut self) {
-        let Operation::Retag(op) = &self.operation else {
-            unreachable!("log_creation must only be called during a retag")
-        };
-        self.history
-            .creations
-            .push(Creation { retag: op.clone(), span: self.machine.current_span() });
-    }
-
-    pub fn log_invalidation(&mut self, tag: SbTag) {
-        let mut span = self.machine.current_span();
-        let (range, cause) = match &self.operation {
-            Operation::Retag(RetagOp { cause, range, permission, .. }) => {
-                if *cause == RetagCause::FnEntry {
-                    span = self.machine.caller_span();
-                }
-                (*range, InvalidationCause::Retag(permission.unwrap(), *cause))
-            }
-            Operation::Access(AccessOp { kind, range, .. }) =>
-                (*range, InvalidationCause::Access(*kind)),
-            Operation::Dealloc(_) => {
-                // This can be reached, but never be relevant later since the entire allocation is
-                // gone now.
-                return;
-            }
-        };
-        self.history.invalidations.push(Invalidation { tag, range, span, cause });
-    }
-
-    pub fn log_protector(&mut self) {
-        let Operation::Retag(op) = &self.operation else {
-            unreachable!("Protectors can only be created during a retag")
-        };
-        self.history
-            .protectors
-            .push(Protection { tag: op.new_tag, span: self.machine.current_span() });
-    }
-
-    pub fn get_logs_relevant_to(
-        &self,
-        tag: SbTag,
-        protector_tag: Option<SbTag>,
-    ) -> Option<TagHistory> {
-        let Some(created) = self.history
-            .creations
-            .iter()
-            .rev()
-            .find_map(|event| {
-                // First, look for a Creation event where the tag and the offset matches. This
-                // ensrues that we pick the right Creation event when a retag isn't uniform due to
-                // Freeze.
-                let range = event.retag.range;
-                if event.retag.new_tag == tag
-                    && self.offset >= range.start
-                    && self.offset < (range.start + range.size)
-                {
-                    Some(event.generate_diagnostic())
-                } else {
-                    None
-                }
-            })
-            .or_else(|| {
-                // If we didn't find anything with a matching offset, just return the event where
-                // the tag was created. This branch is hit when we use a tag at an offset that
-                // doesn't have the tag.
-                self.history.creations.iter().rev().find_map(|event| {
-                    if event.retag.new_tag == tag {
-                        Some(event.generate_diagnostic())
-                    } else {
-                        None
-                    }
-                })
-            }).or_else(|| {
-                // If we didn't find a retag that created this tag, it might be the base tag of
-                // this allocation.
-                if self.history.base.0.tag() == tag {
-                    Some((
-                        format!("{tag:?} was created here, as the base tag for {:?}", self.history.id),
-                        self.history.base.1.data()
-                    ))
-                } else {
-                    None
-                }
-            }) else {
-                // But if we don't have a creation event, this is related to a wildcard, and there
-                // is really nothing we can do to help.
-                return None;
-            };
-
-        let invalidated = self.history.invalidations.iter().rev().find_map(|event| {
-            if event.tag == tag { Some(event.generate_diagnostic()) } else { None }
-        });
-
-        let protected = protector_tag
-            .and_then(|protector| {
-                self.history.protectors.iter().find(|protection| protection.tag == protector)
-            })
-            .map(|protection| {
-                let protected_tag = protection.tag;
-                (format!("{protected_tag:?} is this argument"), protection.span.data())
-            });
-
-        Some(TagHistory { created, invalidated, protected })
-    }
-
-    /// Report a descriptive error when `new` could not be granted from `derived_from`.
-    #[inline(never)] // This is only called on fatal code paths
-    pub(super) fn grant_error(&self, stack: &Stack) -> InterpError<'tcx> {
-        let Operation::Retag(op) = &self.operation else {
-            unreachable!("grant_error should only be called during a retag")
-        };
-        let perm =
-            op.permission.expect("`start_grant` must be called before calling `grant_error`");
-        let action = format!(
-            "trying to retag from {:?} for {:?} permission at {:?}[{:#x}]",
-            op.orig_tag,
-            perm,
-            self.history.id,
-            self.offset.bytes(),
-        );
-        err_sb_ub(
-            format!("{action}{}", error_cause(stack, op.orig_tag)),
-            Some(operation_summary(&op.cause.summary(), self.history.id, op.range)),
-            op.orig_tag.and_then(|orig_tag| self.get_logs_relevant_to(orig_tag, None)),
-        )
-    }
-
-    /// Report a descriptive error when `access` is not permitted based on `tag`.
-    #[inline(never)] // This is only called on fatal code paths
-    pub(super) fn access_error(&self, stack: &Stack) -> InterpError<'tcx> {
-        // Deallocation and retagging also do an access as part of their thing, so handle that here, too.
-        let op = match &self.operation {
-            Operation::Access(op) => op,
-            Operation::Retag(_) => return self.grant_error(stack),
-            Operation::Dealloc(_) => return self.dealloc_error(stack),
-        };
-        let action = format!(
-            "attempting a {access} using {tag:?} at {alloc_id:?}[{offset:#x}]",
-            access = op.kind,
-            tag = op.tag,
-            alloc_id = self.history.id,
-            offset = self.offset.bytes(),
-        );
-        err_sb_ub(
-            format!("{action}{}", error_cause(stack, op.tag)),
-            Some(operation_summary("an access", self.history.id, op.range)),
-            op.tag.and_then(|tag| self.get_logs_relevant_to(tag, None)),
-        )
-    }
-
-    #[inline(never)] // This is only called on fatal code paths
-    pub(super) fn protector_error(&self, item: &Item, kind: ProtectorKind) -> InterpError<'tcx> {
-        let protected = match kind {
-            ProtectorKind::WeakProtector => "weakly protected",
-            ProtectorKind::StrongProtector => "strongly protected",
-        };
-        let call_id = self
-            .machine
-            .threads
-            .all_stacks()
-            .flatten()
-            .map(|frame| {
-                frame.extra.stacked_borrows.as_ref().expect("we should have Stacked Borrows data")
-            })
-            .find(|frame| frame.protected_tags.contains(&item.tag()))
-            .map(|frame| frame.call_id)
-            .unwrap(); // FIXME: Surely we should find something, but a panic seems wrong here?
-        match self.operation {
-            Operation::Dealloc(_) =>
-                err_sb_ub(
-                    format!("deallocating while item {item:?} is {protected} by call {call_id:?}",),
-                    None,
-                    None,
-                ),
-            Operation::Retag(RetagOp { orig_tag: tag, .. })
-            | Operation::Access(AccessOp { tag, .. }) =>
-                err_sb_ub(
-                    format!(
-                        "not granting access to tag {tag:?} because that would remove {item:?} which is {protected} because it is an argument of call {call_id:?}",
-                    ),
-                    None,
-                    tag.and_then(|tag| self.get_logs_relevant_to(tag, Some(item.tag()))),
-                ),
-        }
-    }
-
-    #[inline(never)] // This is only called on fatal code paths
-    pub fn dealloc_error(&self, stack: &Stack) -> InterpError<'tcx> {
-        let Operation::Dealloc(op) = &self.operation else {
-            unreachable!("dealloc_error should only be called during a deallocation")
-        };
-        err_sb_ub(
-            format!(
-                "attempting deallocation using {tag:?} at {alloc_id:?}{cause}",
-                tag = op.tag,
-                alloc_id = self.history.id,
-                cause = error_cause(stack, op.tag),
-            ),
-            None,
-            op.tag.and_then(|tag| self.get_logs_relevant_to(tag, None)),
-        )
-    }
-
-    #[inline(never)]
-    pub fn check_tracked_tag_popped(&self, item: &Item, global: &GlobalStateInner) {
-        if !global.tracked_pointer_tags.contains(&item.tag()) {
-            return;
-        }
-        let summary = match self.operation {
-            Operation::Dealloc(_) => None,
-            Operation::Access(AccessOp { kind, tag, .. }) => Some((tag, kind)),
-            Operation::Retag(RetagOp { orig_tag, permission, .. }) => {
-                let kind = match permission
-                    .expect("start_grant should set the current permission before popping a tag")
-                {
-                    Permission::SharedReadOnly => AccessKind::Read,
-                    Permission::Unique => AccessKind::Write,
-                    Permission::SharedReadWrite | Permission::Disabled => {
-                        panic!("Only SharedReadOnly and Unique retags can pop tags");
-                    }
-                };
-                Some((orig_tag, kind))
-            }
-        };
-        self.machine.emit_diagnostic(NonHaltingDiagnostic::PoppedPointerTag(*item, summary));
-    }
-}
-
-fn operation_summary(operation: &str, alloc_id: AllocId, alloc_range: AllocRange) -> String {
-    format!("this error occurs as part of {operation} at {alloc_id:?}{alloc_range:?}")
-}
-
-fn error_cause(stack: &Stack, prov_extra: ProvenanceExtra) -> &'static str {
-    if let ProvenanceExtra::Concrete(tag) = prov_extra {
-        if (0..stack.len())
-            .map(|i| stack.get(i).unwrap())
-            .any(|item| item.tag() == tag && item.perm() != Permission::Disabled)
-        {
-            ", but that tag only grants SharedReadOnly permission for this location"
-        } else {
-            ", but that tag does not exist in the borrow stack for this location"
-        }
-    } else {
-        ", but no exposed tags have suitable permission in the borrow stack for this location"
-    }
-}
-
-impl RetagCause {
-    fn summary(&self) -> String {
-        match self {
-            RetagCause::Normal => "retag",
-            RetagCause::FnEntry => "FnEntry retag",
-            RetagCause::FnReturn => "FnReturn retag",
-            RetagCause::TwoPhase => "two-phase retag",
-        }
-        .to_string()
-    }
-}
diff --git a/src/tools/miri/src/stacked_borrows/item.rs b/src/tools/miri/src/stacked_borrows/item.rs
deleted file mode 100644 (file)
index 709b27d..0000000
+++ /dev/null
@@ -1,104 +0,0 @@
-use crate::stacked_borrows::SbTag;
-use std::fmt;
-use std::num::NonZeroU64;
-
-/// An item in the per-location borrow stack.
-#[derive(Copy, Clone, Hash, PartialEq, Eq)]
-pub struct Item(u64);
-
-// An Item contains 3 bitfields:
-// * Bits 0-61 store an SbTag
-// * Bits 61-63 store a Permission
-// * Bit 64 stores a flag which indicates if we have a protector
-const TAG_MASK: u64 = u64::MAX >> 3;
-const PERM_MASK: u64 = 0x3 << 61;
-const PROTECTED_MASK: u64 = 0x1 << 63;
-
-const PERM_SHIFT: u64 = 61;
-const PROTECTED_SHIFT: u64 = 63;
-
-impl Item {
-    pub fn new(tag: SbTag, perm: Permission, protected: bool) -> Self {
-        assert!(tag.0.get() <= TAG_MASK);
-        let packed_tag = tag.0.get();
-        let packed_perm = perm.to_bits() << PERM_SHIFT;
-        let packed_protected = u64::from(protected) << PROTECTED_SHIFT;
-
-        let new = Self(packed_tag | packed_perm | packed_protected);
-
-        debug_assert!(new.tag() == tag);
-        debug_assert!(new.perm() == perm);
-        debug_assert!(new.protected() == protected);
-
-        new
-    }
-
-    /// The pointers the permission is granted to.
-    pub fn tag(self) -> SbTag {
-        SbTag(NonZeroU64::new(self.0 & TAG_MASK).unwrap())
-    }
-
-    /// The permission this item grants.
-    pub fn perm(self) -> Permission {
-        Permission::from_bits((self.0 & PERM_MASK) >> PERM_SHIFT)
-    }
-
-    /// Whether or not there is a protector for this tag
-    pub fn protected(self) -> bool {
-        self.0 & PROTECTED_MASK > 0
-    }
-
-    /// Set the Permission stored in this Item
-    pub fn set_permission(&mut self, perm: Permission) {
-        // Clear the current set permission
-        self.0 &= !PERM_MASK;
-        // Write Permission::Disabled to the Permission bits
-        self.0 |= perm.to_bits() << PERM_SHIFT;
-    }
-}
-
-impl fmt::Debug for Item {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        write!(f, "[{:?} for {:?}]", self.perm(), self.tag())
-    }
-}
-
-/// Indicates which permission is granted (by this item to some pointers)
-#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
-pub enum Permission {
-    /// Grants unique mutable access.
-    Unique,
-    /// Grants shared mutable access.
-    SharedReadWrite,
-    /// Grants shared read-only access.
-    SharedReadOnly,
-    /// Grants no access, but separates two groups of SharedReadWrite so they are not
-    /// all considered mutually compatible.
-    Disabled,
-}
-
-impl Permission {
-    const UNIQUE: u64 = 0;
-    const SHARED_READ_WRITE: u64 = 1;
-    const SHARED_READ_ONLY: u64 = 2;
-    const DISABLED: u64 = 3;
-
-    fn to_bits(self) -> u64 {
-        match self {
-            Permission::Unique => Self::UNIQUE,
-            Permission::SharedReadWrite => Self::SHARED_READ_WRITE,
-            Permission::SharedReadOnly => Self::SHARED_READ_ONLY,
-            Permission::Disabled => Self::DISABLED,
-        }
-    }
-
-    fn from_bits(perm: u64) -> Self {
-        match perm {
-            Self::UNIQUE => Permission::Unique,
-            Self::SHARED_READ_WRITE => Permission::SharedReadWrite,
-            Self::SHARED_READ_ONLY => Permission::SharedReadOnly,
-            Self::DISABLED => Permission::Disabled,
-            _ => unreachable!(),
-        }
-    }
-}
diff --git a/src/tools/miri/src/stacked_borrows/mod.rs b/src/tools/miri/src/stacked_borrows/mod.rs
deleted file mode 100644 (file)
index 4e369f4..0000000
+++ /dev/null
@@ -1,1210 +0,0 @@
-//! Implements "Stacked Borrows".  See <https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md>
-//! for further information.
-
-use log::trace;
-use std::cell::RefCell;
-use std::cmp;
-use std::fmt;
-use std::fmt::Write;
-use std::num::NonZeroU64;
-
-use rustc_data_structures::fx::{FxHashMap, FxHashSet};
-use rustc_hir::Mutability;
-use rustc_middle::mir::RetagKind;
-use rustc_middle::ty::{
-    self,
-    layout::{HasParamEnv, LayoutOf},
-};
-use rustc_target::abi::Abi;
-use rustc_target::abi::Size;
-use smallvec::SmallVec;
-
-use crate::*;
-
-pub mod diagnostics;
-use diagnostics::{AllocHistory, DiagnosticCx, DiagnosticCxBuilder, RetagCause, TagHistory};
-
-mod item;
-pub use item::{Item, Permission};
-mod stack;
-pub use stack::Stack;
-
-pub type CallId = NonZeroU64;
-
-// Even reading memory can have effects on the stack, so we need a `RefCell` here.
-pub type AllocExtra = RefCell<Stacks>;
-
-/// Tracking pointer provenance
-#[derive(Copy, Clone, Hash, PartialEq, Eq)]
-pub struct SbTag(NonZeroU64);
-
-impl SbTag {
-    pub fn new(i: u64) -> Option<Self> {
-        NonZeroU64::new(i).map(SbTag)
-    }
-
-    // The default to be used when SB is disabled
-    #[allow(clippy::should_implement_trait)]
-    pub fn default() -> Self {
-        Self::new(1).unwrap()
-    }
-}
-
-impl fmt::Debug for SbTag {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        write!(f, "<{}>", self.0)
-    }
-}
-
-#[derive(Debug)]
-pub struct FrameExtra {
-    /// The ID of the call this frame corresponds to.
-    call_id: CallId,
-
-    /// If this frame is protecting any tags, they are listed here. We use this list to do
-    /// incremental updates of the global list of protected tags stored in the
-    /// `stacked_borrows::GlobalState` upon function return, and if we attempt to pop a protected
-    /// tag, to identify which call is responsible for protecting the tag.
-    /// See `Stack::item_invalidated` for more explanation.
-    ///
-    /// This will contain one tag per reference passed to the function, so
-    /// a size of 2 is enough for the vast majority of functions.
-    protected_tags: SmallVec<[SbTag; 2]>,
-}
-
-impl VisitTags for FrameExtra {
-    fn visit_tags(&self, _visit: &mut dyn FnMut(SbTag)) {
-        // `protected_tags` are fine to GC.
-    }
-}
-
-/// Extra per-allocation state.
-#[derive(Clone, Debug)]
-pub struct Stacks {
-    // Even reading memory can have effects on the stack, so we need a `RefCell` here.
-    stacks: RangeMap<Stack>,
-    /// Stores past operations on this allocation
-    history: AllocHistory,
-    /// The set of tags that have been exposed inside this allocation.
-    exposed_tags: FxHashSet<SbTag>,
-    /// Whether this memory has been modified since the last time the tag GC ran
-    modified_since_last_gc: bool,
-}
-
-/// The flavor of the protector.
-#[derive(Copy, Clone, Debug)]
-enum ProtectorKind {
-    /// Protected against aliasing violations from other pointers.
-    ///
-    /// Items protected like this cause UB when they are invalidated, *but* the pointer itself may
-    /// still be used to issue a deallocation.
-    ///
-    /// This is required for LLVM IR pointers that are `noalias` but *not* `dereferenceable`.
-    WeakProtector,
-
-    /// Protected against any kind of invalidation.
-    ///
-    /// Items protected like this cause UB when they are invalidated or the memory is deallocated.
-    /// This is strictly stronger protection than `WeakProtector`.
-    ///
-    /// This is required for LLVM IR pointers that are `dereferenceable` (and also allows `noalias`).
-    StrongProtector,
-}
-
-/// Extra global state, available to the memory access hooks.
-#[derive(Debug)]
-pub struct GlobalStateInner {
-    /// Next unused pointer ID (tag).
-    next_ptr_tag: SbTag,
-    /// Table storing the "base" tag for each allocation.
-    /// The base tag is the one used for the initial pointer.
-    /// We need this in a separate table to handle cyclic statics.
-    base_ptr_tags: FxHashMap<AllocId, SbTag>,
-    /// Next unused call ID (for protectors).
-    next_call_id: CallId,
-    /// All currently protected tags, and the status of their protection.
-    /// An item is protected if its tag is in this set, *and* it has the "protected" bit set.
-    /// We add tags to this when they are created with a protector in `reborrow`, and
-    /// we remove tags from this when the call which is protecting them returns, in
-    /// `GlobalStateInner::end_call`. See `Stack::item_invalidated` for more details.
-    protected_tags: FxHashMap<SbTag, ProtectorKind>,
-    /// The pointer ids to trace
-    tracked_pointer_tags: FxHashSet<SbTag>,
-    /// The call ids to trace
-    tracked_call_ids: FxHashSet<CallId>,
-    /// Whether to recurse into datatypes when searching for pointers to retag.
-    retag_fields: RetagFields,
-}
-
-#[derive(Copy, Clone, Debug)]
-pub enum RetagFields {
-    /// Don't retag any fields.
-    No,
-    /// Retag all fields.
-    Yes,
-    /// Only retag fields of types with Scalar and ScalarPair layout,
-    /// to match the LLVM `noalias` we generate.
-    OnlyScalar,
-}
-
-impl VisitTags for GlobalStateInner {
-    fn visit_tags(&self, _visit: &mut dyn FnMut(SbTag)) {
-        // The only candidate is base_ptr_tags, and that does not need visiting since we don't ever
-        // GC the bottommost tag.
-    }
-}
-
-/// We need interior mutable access to the global state.
-pub type GlobalState = RefCell<GlobalStateInner>;
-
-/// Indicates which kind of access is being performed.
-#[derive(Copy, Clone, Hash, PartialEq, Eq, Debug)]
-pub enum AccessKind {
-    Read,
-    Write,
-}
-
-impl fmt::Display for AccessKind {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        match self {
-            AccessKind::Read => write!(f, "read access"),
-            AccessKind::Write => write!(f, "write access"),
-        }
-    }
-}
-
-/// Indicates which kind of reference is being created.
-/// Used by high-level `reborrow` to compute which permissions to grant to the
-/// new pointer.
-#[derive(Copy, Clone, Hash, PartialEq, Eq)]
-pub enum RefKind {
-    /// `&mut` and `Box`.
-    Unique { two_phase: bool },
-    /// `&` with or without interior mutability.
-    Shared,
-    /// `*mut`/`*const` (raw pointers).
-    Raw { mutable: bool },
-}
-
-impl fmt::Display for RefKind {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        match self {
-            RefKind::Unique { two_phase: false } => write!(f, "unique reference"),
-            RefKind::Unique { two_phase: true } => write!(f, "unique reference (two-phase)"),
-            RefKind::Shared => write!(f, "shared reference"),
-            RefKind::Raw { mutable: true } => write!(f, "raw (mutable) pointer"),
-            RefKind::Raw { mutable: false } => write!(f, "raw (constant) pointer"),
-        }
-    }
-}
-
-/// Utilities for initialization and ID generation
-impl GlobalStateInner {
-    pub fn new(
-        tracked_pointer_tags: FxHashSet<SbTag>,
-        tracked_call_ids: FxHashSet<CallId>,
-        retag_fields: RetagFields,
-    ) -> Self {
-        GlobalStateInner {
-            next_ptr_tag: SbTag(NonZeroU64::new(1).unwrap()),
-            base_ptr_tags: FxHashMap::default(),
-            next_call_id: NonZeroU64::new(1).unwrap(),
-            protected_tags: FxHashMap::default(),
-            tracked_pointer_tags,
-            tracked_call_ids,
-            retag_fields,
-        }
-    }
-
-    /// Generates a new pointer tag. Remember to also check track_pointer_tags and log its creation!
-    fn new_ptr(&mut self) -> SbTag {
-        let id = self.next_ptr_tag;
-        self.next_ptr_tag = SbTag(NonZeroU64::new(id.0.get() + 1).unwrap());
-        id
-    }
-
-    pub fn new_frame(&mut self, machine: &MiriMachine<'_, '_>) -> FrameExtra {
-        let call_id = self.next_call_id;
-        trace!("new_frame: Assigning call ID {}", call_id);
-        if self.tracked_call_ids.contains(&call_id) {
-            machine.emit_diagnostic(NonHaltingDiagnostic::CreatedCallId(call_id));
-        }
-        self.next_call_id = NonZeroU64::new(call_id.get() + 1).unwrap();
-        FrameExtra { call_id, protected_tags: SmallVec::new() }
-    }
-
-    pub fn end_call(&mut self, frame: &machine::FrameData<'_>) {
-        for tag in &frame
-            .stacked_borrows
-            .as_ref()
-            .expect("we should have Stacked Borrows data")
-            .protected_tags
-        {
-            self.protected_tags.remove(tag);
-        }
-    }
-
-    pub fn base_ptr_tag(&mut self, id: AllocId, machine: &MiriMachine<'_, '_>) -> SbTag {
-        self.base_ptr_tags.get(&id).copied().unwrap_or_else(|| {
-            let tag = self.new_ptr();
-            if self.tracked_pointer_tags.contains(&tag) {
-                machine.emit_diagnostic(NonHaltingDiagnostic::CreatedPointerTag(tag.0, None, None));
-            }
-            trace!("New allocation {:?} has base tag {:?}", id, tag);
-            self.base_ptr_tags.try_insert(id, tag).unwrap();
-            tag
-        })
-    }
-}
-
-/// Error reporting
-pub fn err_sb_ub<'tcx>(
-    msg: String,
-    help: Option<String>,
-    history: Option<TagHistory>,
-) -> InterpError<'tcx> {
-    err_machine_stop!(TerminationInfo::StackedBorrowsUb { msg, help, history })
-}
-
-// # Stacked Borrows Core Begin
-
-/// We need to make at least the following things true:
-///
-/// U1: After creating a `Uniq`, it is at the top.
-/// U2: If the top is `Uniq`, accesses must be through that `Uniq` or remove it.
-/// U3: If an access happens with a `Uniq`, it requires the `Uniq` to be in the stack.
-///
-/// F1: After creating a `&`, the parts outside `UnsafeCell` have our `SharedReadOnly` on top.
-/// F2: If a write access happens, it pops the `SharedReadOnly`.  This has three pieces:
-///     F2a: If a write happens granted by an item below our `SharedReadOnly`, the `SharedReadOnly`
-///          gets popped.
-///     F2b: No `SharedReadWrite` or `Unique` will ever be added on top of our `SharedReadOnly`.
-/// F3: If an access happens with an `&` outside `UnsafeCell`,
-///     it requires the `SharedReadOnly` to still be in the stack.
-
-/// Core relation on `Permission` to define which accesses are allowed
-impl Permission {
-    /// This defines for a given permission, whether it permits the given kind of access.
-    fn grants(self, access: AccessKind) -> bool {
-        // Disabled grants nothing. Otherwise, all items grant read access, and except for SharedReadOnly they grant write access.
-        self != Permission::Disabled
-            && (access == AccessKind::Read || self != Permission::SharedReadOnly)
-    }
-}
-
-/// Determines whether an item was invalidated by a conflicting access, or by deallocation.
-#[derive(Copy, Clone, Debug)]
-enum ItemInvalidationCause {
-    Conflict,
-    Dealloc,
-}
-
-/// Core per-location operations: access, dealloc, reborrow.
-impl<'tcx> Stack {
-    /// Find the first write-incompatible item above the given one --
-    /// i.e, find the height to which the stack will be truncated when writing to `granting`.
-    fn find_first_write_incompatible(&self, granting: usize) -> usize {
-        let perm = self.get(granting).unwrap().perm();
-        match perm {
-            Permission::SharedReadOnly => bug!("Cannot use SharedReadOnly for writing"),
-            Permission::Disabled => bug!("Cannot use Disabled for anything"),
-            Permission::Unique => {
-                // On a write, everything above us is incompatible.
-                granting + 1
-            }
-            Permission::SharedReadWrite => {
-                // The SharedReadWrite *just* above us are compatible, to skip those.
-                let mut idx = granting + 1;
-                while let Some(item) = self.get(idx) {
-                    if item.perm() == Permission::SharedReadWrite {
-                        // Go on.
-                        idx += 1;
-                    } else {
-                        // Found first incompatible!
-                        break;
-                    }
-                }
-                idx
-            }
-        }
-    }
-
-    /// Check if the given item is protected.
-    ///
-    /// The `provoking_access` argument is only used to produce diagnostics.
-    /// It is `Some` when we are granting the contained access for said tag, and it is
-    /// `None` during a deallocation.
-    /// Within `provoking_access, the `AllocRange` refers the entire operation, and
-    /// the `Size` refers to the specific location in the `AllocRange` that we are
-    /// currently checking.
-    fn item_invalidated(
-        item: &Item,
-        global: &GlobalStateInner,
-        dcx: &mut DiagnosticCx<'_, '_, '_, 'tcx>,
-        cause: ItemInvalidationCause,
-    ) -> InterpResult<'tcx> {
-        if !global.tracked_pointer_tags.is_empty() {
-            dcx.check_tracked_tag_popped(item, global);
-        }
-
-        if !item.protected() {
-            return Ok(());
-        }
-
-        // We store tags twice, once in global.protected_tags and once in each call frame.
-        // We do this because consulting a single global set in this function is faster
-        // than attempting to search all call frames in the program for the `FrameExtra`
-        // (if any) which is protecting the popped tag.
-        //
-        // This duplication trades off making `end_call` slower to make this function faster. This
-        // trade-off is profitable in practice for a combination of two reasons.
-        // 1. A single protected tag can (and does in some programs) protect thousands of `Item`s.
-        //    Therefore, adding overhead in function call/return is profitable even if it only
-        //    saves a little work in this function.
-        // 2. Most frames protect only one or two tags. So this duplicative global turns a search
-        //    which ends up about linear in the number of protected tags in the program into a
-        //    constant time check (and a slow linear, because the tags in the frames aren't contiguous).
-        if let Some(&protector_kind) = global.protected_tags.get(&item.tag()) {
-            // The only way this is okay is if the protector is weak and we are deallocating with
-            // the right pointer.
-            let allowed = matches!(cause, ItemInvalidationCause::Dealloc)
-                && matches!(protector_kind, ProtectorKind::WeakProtector);
-            if !allowed {
-                return Err(dcx.protector_error(item, protector_kind).into());
-            }
-        }
-        Ok(())
-    }
-
-    /// Test if a memory `access` using pointer tagged `tag` is granted.
-    /// If yes, return the index of the item that granted it.
-    /// `range` refers the entire operation, and `offset` refers to the specific offset into the
-    /// allocation that we are currently checking.
-    fn access(
-        &mut self,
-        access: AccessKind,
-        tag: ProvenanceExtra,
-        global: &GlobalStateInner,
-        dcx: &mut DiagnosticCx<'_, '_, '_, 'tcx>,
-        exposed_tags: &FxHashSet<SbTag>,
-    ) -> InterpResult<'tcx> {
-        // Two main steps: Find granting item, remove incompatible items above.
-
-        // Step 1: Find granting item.
-        let granting_idx =
-            self.find_granting(access, tag, exposed_tags).map_err(|()| dcx.access_error(self))?;
-
-        // Step 2: Remove incompatible items above them.  Make sure we do not remove protected
-        // items.  Behavior differs for reads and writes.
-        // In case of wildcards/unknown matches, we remove everything that is *definitely* gone.
-        if access == AccessKind::Write {
-            // Remove everything above the write-compatible items, like a proper stack. This makes sure read-only and unique
-            // pointers become invalid on write accesses (ensures F2a, and ensures U2 for write accesses).
-            let first_incompatible_idx = if let Some(granting_idx) = granting_idx {
-                // The granting_idx *might* be approximate, but any lower idx would remove more
-                // things. Even if this is a Unique and the lower idx is an SRW (which removes
-                // less), there is an SRW group boundary here so strictly more would get removed.
-                self.find_first_write_incompatible(granting_idx)
-            } else {
-                // We are writing to something in the unknown part.
-                // There is a SRW group boundary between the unknown and the known, so everything is incompatible.
-                0
-            };
-            self.pop_items_after(first_incompatible_idx, |item| {
-                Stack::item_invalidated(&item, global, dcx, ItemInvalidationCause::Conflict)?;
-                dcx.log_invalidation(item.tag());
-                Ok(())
-            })?;
-        } else {
-            // On a read, *disable* all `Unique` above the granting item.  This ensures U2 for read accesses.
-            // The reason this is not following the stack discipline (by removing the first Unique and
-            // everything on top of it) is that in `let raw = &mut *x as *mut _; let _val = *x;`, the second statement
-            // would pop the `Unique` from the reborrow of the first statement, and subsequently also pop the
-            // `SharedReadWrite` for `raw`.
-            // This pattern occurs a lot in the standard library: create a raw pointer, then also create a shared
-            // reference and use that.
-            // We *disable* instead of removing `Unique` to avoid "connecting" two neighbouring blocks of SRWs.
-            let first_incompatible_idx = if let Some(granting_idx) = granting_idx {
-                // The granting_idx *might* be approximate, but any lower idx would disable more things.
-                granting_idx + 1
-            } else {
-                // We are reading from something in the unknown part. That means *all* `Unique` we know about are dead now.
-                0
-            };
-            self.disable_uniques_starting_at(first_incompatible_idx, |item| {
-                Stack::item_invalidated(&item, global, dcx, ItemInvalidationCause::Conflict)?;
-                dcx.log_invalidation(item.tag());
-                Ok(())
-            })?;
-        }
-
-        // If this was an approximate action, we now collapse everything into an unknown.
-        if granting_idx.is_none() || matches!(tag, ProvenanceExtra::Wildcard) {
-            // Compute the upper bound of the items that remain.
-            // (This is why we did all the work above: to reduce the items we have to consider here.)
-            let mut max = NonZeroU64::new(1).unwrap();
-            for i in 0..self.len() {
-                let item = self.get(i).unwrap();
-                // Skip disabled items, they cannot be matched anyway.
-                if !matches!(item.perm(), Permission::Disabled) {
-                    // We are looking for a strict upper bound, so add 1 to this tag.
-                    max = cmp::max(item.tag().0.checked_add(1).unwrap(), max);
-                }
-            }
-            if let Some(unk) = self.unknown_bottom() {
-                max = cmp::max(unk.0, max);
-            }
-            // Use `max` as new strict upper bound for everything.
-            trace!(
-                "access: forgetting stack to upper bound {max} due to wildcard or unknown access"
-            );
-            self.set_unknown_bottom(SbTag(max));
-        }
-
-        // Done.
-        Ok(())
-    }
-
-    /// Deallocate a location: Like a write access, but also there must be no
-    /// active protectors at all because we will remove all items.
-    fn dealloc(
-        &mut self,
-        tag: ProvenanceExtra,
-        global: &GlobalStateInner,
-        dcx: &mut DiagnosticCx<'_, '_, '_, 'tcx>,
-        exposed_tags: &FxHashSet<SbTag>,
-    ) -> InterpResult<'tcx> {
-        // Step 1: Make a write access.
-        // As part of this we do regular protector checking, i.e. even weakly protected items cause UB when popped.
-        self.access(AccessKind::Write, tag, global, dcx, exposed_tags)?;
-
-        // Step 2: Pretend we remove the remaining items, checking if any are strongly protected.
-        for idx in (0..self.len()).rev() {
-            let item = self.get(idx).unwrap();
-            Stack::item_invalidated(&item, global, dcx, ItemInvalidationCause::Dealloc)?;
-        }
-
-        Ok(())
-    }
-
-    /// Derive a new pointer from one with the given tag.
-    ///
-    /// `access` indicates which kind of memory access this retag itself should correspond to.
-    fn grant(
-        &mut self,
-        derived_from: ProvenanceExtra,
-        new: Item,
-        access: Option<AccessKind>,
-        global: &GlobalStateInner,
-        dcx: &mut DiagnosticCx<'_, '_, '_, 'tcx>,
-        exposed_tags: &FxHashSet<SbTag>,
-    ) -> InterpResult<'tcx> {
-        dcx.start_grant(new.perm());
-
-        // Compute where to put the new item.
-        // Either way, we ensure that we insert the new item in a way such that between
-        // `derived_from` and the new one, there are only items *compatible with* `derived_from`.
-        let new_idx = if let Some(access) = access {
-            // Simple case: We are just a regular memory access, and then push our thing on top,
-            // like a regular stack.
-            // This ensures F2b for `Unique`, by removing offending `SharedReadOnly`.
-            self.access(access, derived_from, global, dcx, exposed_tags)?;
-
-            // We insert "as far up as possible": We know only compatible items are remaining
-            // on top of `derived_from`, and we want the new item at the top so that we
-            // get the strongest possible guarantees.
-            // This ensures U1 and F1.
-            self.len()
-        } else {
-            // The tricky case: creating a new SRW permission without actually being an access.
-            assert!(new.perm() == Permission::SharedReadWrite);
-
-            // First we figure out which item grants our parent (`derived_from`) this kind of access.
-            // We use that to determine where to put the new item.
-            let granting_idx = self
-                .find_granting(AccessKind::Write, derived_from, exposed_tags)
-                .map_err(|()| dcx.grant_error(self))?;
-
-            let (Some(granting_idx), ProvenanceExtra::Concrete(_)) = (granting_idx, derived_from) else {
-                // The parent is a wildcard pointer or matched the unknown bottom.
-                // This is approximate. Nobody knows what happened, so forget everything.
-                // The new thing is SRW anyway, so we cannot push it "on top of the unkown part"
-                // (for all we know, it might join an SRW group inside the unknown).
-                trace!("reborrow: forgetting stack entirely due to SharedReadWrite reborrow from wildcard or unknown");
-                self.set_unknown_bottom(global.next_ptr_tag);
-                return Ok(());
-            };
-
-            // SharedReadWrite can coexist with "existing loans", meaning they don't act like a write
-            // access.  Instead of popping the stack, we insert the item at the place the stack would
-            // be popped to (i.e., we insert it above all the write-compatible items).
-            // This ensures F2b by adding the new item below any potentially existing `SharedReadOnly`.
-            self.find_first_write_incompatible(granting_idx)
-        };
-
-        // Put the new item there.
-        trace!("reborrow: adding item {:?}", new);
-        self.insert(new_idx, new);
-        Ok(())
-    }
-}
-// # Stacked Borrows Core End
-
-/// Integration with the SbTag garbage collector
-impl Stacks {
-    pub fn remove_unreachable_tags(&mut self, live_tags: &FxHashSet<SbTag>) {
-        if self.modified_since_last_gc {
-            for stack in self.stacks.iter_mut_all() {
-                if stack.len() > 64 {
-                    stack.retain(live_tags);
-                }
-            }
-            self.modified_since_last_gc = false;
-        }
-    }
-}
-
-impl VisitTags for Stacks {
-    fn visit_tags(&self, visit: &mut dyn FnMut(SbTag)) {
-        for tag in self.exposed_tags.iter().copied() {
-            visit(tag);
-        }
-    }
-}
-
-/// Map per-stack operations to higher-level per-location-range operations.
-impl<'tcx> Stacks {
-    /// Creates a new stack with an initial tag. For diagnostic purposes, we also need to know
-    /// the [`AllocId`] of the allocation this is associated with.
-    fn new(
-        size: Size,
-        perm: Permission,
-        tag: SbTag,
-        id: AllocId,
-        machine: &MiriMachine<'_, '_>,
-    ) -> Self {
-        let item = Item::new(tag, perm, false);
-        let stack = Stack::new(item);
-
-        Stacks {
-            stacks: RangeMap::new(size, stack),
-            history: AllocHistory::new(id, item, machine),
-            exposed_tags: FxHashSet::default(),
-            modified_since_last_gc: false,
-        }
-    }
-
-    /// Call `f` on every stack in the range.
-    fn for_each(
-        &mut self,
-        range: AllocRange,
-        mut dcx_builder: DiagnosticCxBuilder<'_, '_, 'tcx>,
-        mut f: impl FnMut(
-            &mut Stack,
-            &mut DiagnosticCx<'_, '_, '_, 'tcx>,
-            &mut FxHashSet<SbTag>,
-        ) -> InterpResult<'tcx>,
-    ) -> InterpResult<'tcx> {
-        self.modified_since_last_gc = true;
-        for (offset, stack) in self.stacks.iter_mut(range.start, range.size) {
-            let mut dcx = dcx_builder.build(&mut self.history, offset);
-            f(stack, &mut dcx, &mut self.exposed_tags)?;
-            dcx_builder = dcx.unbuild();
-        }
-        Ok(())
-    }
-}
-
-/// Glue code to connect with Miri Machine Hooks
-impl Stacks {
-    pub fn new_allocation(
-        id: AllocId,
-        size: Size,
-        state: &GlobalState,
-        kind: MemoryKind<MiriMemoryKind>,
-        machine: &MiriMachine<'_, '_>,
-    ) -> Self {
-        let mut extra = state.borrow_mut();
-        let (base_tag, perm) = match kind {
-            // New unique borrow. This tag is not accessible by the program,
-            // so it will only ever be used when using the local directly (i.e.,
-            // not through a pointer). That is, whenever we directly write to a local, this will pop
-            // everything else off the stack, invalidating all previous pointers,
-            // and in particular, *all* raw pointers.
-            MemoryKind::Stack => (extra.base_ptr_tag(id, machine), Permission::Unique),
-            // Everything else is shared by default.
-            _ => (extra.base_ptr_tag(id, machine), Permission::SharedReadWrite),
-        };
-        Stacks::new(size, perm, base_tag, id, machine)
-    }
-
-    #[inline(always)]
-    pub fn before_memory_read<'tcx, 'mir, 'ecx>(
-        &mut self,
-        alloc_id: AllocId,
-        tag: ProvenanceExtra,
-        range: AllocRange,
-        machine: &'ecx MiriMachine<'mir, 'tcx>,
-    ) -> InterpResult<'tcx>
-    where
-        'tcx: 'ecx,
-    {
-        trace!(
-            "read access with tag {:?}: {:?}, size {}",
-            tag,
-            Pointer::new(alloc_id, range.start),
-            range.size.bytes()
-        );
-        let dcx = DiagnosticCxBuilder::read(machine, tag, range);
-        let state = machine.stacked_borrows.as_ref().unwrap().borrow();
-        self.for_each(range, dcx, |stack, dcx, exposed_tags| {
-            stack.access(AccessKind::Read, tag, &state, dcx, exposed_tags)
-        })
-    }
-
-    #[inline(always)]
-    pub fn before_memory_write<'tcx>(
-        &mut self,
-        alloc_id: AllocId,
-        tag: ProvenanceExtra,
-        range: AllocRange,
-        machine: &mut MiriMachine<'_, 'tcx>,
-    ) -> InterpResult<'tcx> {
-        trace!(
-            "write access with tag {:?}: {:?}, size {}",
-            tag,
-            Pointer::new(alloc_id, range.start),
-            range.size.bytes()
-        );
-        let dcx = DiagnosticCxBuilder::write(machine, tag, range);
-        let state = machine.stacked_borrows.as_ref().unwrap().borrow();
-        self.for_each(range, dcx, |stack, dcx, exposed_tags| {
-            stack.access(AccessKind::Write, tag, &state, dcx, exposed_tags)
-        })
-    }
-
-    #[inline(always)]
-    pub fn before_memory_deallocation<'tcx>(
-        &mut self,
-        alloc_id: AllocId,
-        tag: ProvenanceExtra,
-        range: AllocRange,
-        machine: &mut MiriMachine<'_, 'tcx>,
-    ) -> InterpResult<'tcx> {
-        trace!("deallocation with tag {:?}: {:?}, size {}", tag, alloc_id, range.size.bytes());
-        let dcx = DiagnosticCxBuilder::dealloc(machine, tag);
-        let state = machine.stacked_borrows.as_ref().unwrap().borrow();
-        self.for_each(range, dcx, |stack, dcx, exposed_tags| {
-            stack.dealloc(tag, &state, dcx, exposed_tags)
-        })?;
-        Ok(())
-    }
-}
-
-/// Retagging/reborrowing.  There is some policy in here, such as which permissions
-/// to grant for which references, and when to add protectors.
-impl<'mir: 'ecx, 'tcx: 'mir, 'ecx> EvalContextPrivExt<'mir, 'tcx, 'ecx>
-    for crate::MiriInterpCx<'mir, 'tcx>
-{
-}
-trait EvalContextPrivExt<'mir: 'ecx, 'tcx: 'mir, 'ecx>: crate::MiriInterpCxExt<'mir, 'tcx> {
-    /// Returns the `AllocId` the reborrow was done in, if some actual borrow stack manipulation
-    /// happened.
-    fn reborrow(
-        &mut self,
-        place: &MPlaceTy<'tcx, Provenance>,
-        size: Size,
-        kind: RefKind,
-        retag_cause: RetagCause, // What caused this retag, for diagnostics only
-        new_tag: SbTag,
-        protect: Option<ProtectorKind>,
-    ) -> InterpResult<'tcx, Option<AllocId>> {
-        let this = self.eval_context_mut();
-
-        // It is crucial that this gets called on all code paths, to ensure we track tag creation.
-        let log_creation = |this: &MiriInterpCx<'mir, 'tcx>,
-                            loc: Option<(AllocId, Size, ProvenanceExtra)>| // alloc_id, base_offset, orig_tag
-         -> InterpResult<'tcx> {
-            let global = this.machine.stacked_borrows.as_ref().unwrap().borrow();
-            let ty = place.layout.ty;
-            if global.tracked_pointer_tags.contains(&new_tag) {
-                let mut kind_str = format!("{kind}");
-                match kind {
-                    RefKind::Unique { two_phase: false }
-                        if !ty.is_unpin(*this.tcx, this.param_env()) =>
-                    {
-                        write!(kind_str, " (!Unpin pointee type {ty})").unwrap()
-                    },
-                    RefKind::Shared
-                        if !ty.is_freeze(*this.tcx, this.param_env()) =>
-                    {
-                        write!(kind_str, " (!Freeze pointee type {ty})").unwrap()
-                    },
-                    _ => write!(kind_str, " (pointee type {ty})").unwrap(),
-                };
-                this.emit_diagnostic(NonHaltingDiagnostic::CreatedPointerTag(
-                    new_tag.0,
-                    Some(kind_str),
-                    loc.map(|(alloc_id, base_offset, orig_tag)| (alloc_id, alloc_range(base_offset, size), orig_tag)),
-                ));
-            }
-            drop(global); // don't hold that reference any longer than we have to
-
-            let Some((alloc_id, base_offset, orig_tag)) = loc else {
-                return Ok(())
-            };
-
-            let (_size, _align, alloc_kind) = this.get_alloc_info(alloc_id);
-            match alloc_kind {
-                AllocKind::LiveData => {
-                    // This should have alloc_extra data, but `get_alloc_extra` can still fail
-                    // if converting this alloc_id from a global to a local one
-                    // uncovers a non-supported `extern static`.
-                    let extra = this.get_alloc_extra(alloc_id)?;
-                    let mut stacked_borrows = extra
-                        .stacked_borrows
-                        .as_ref()
-                        .expect("we should have Stacked Borrows data")
-                        .borrow_mut();
-                    // Note that we create a *second* `DiagnosticCxBuilder` below for the actual retag.
-                    // FIXME: can this be done cleaner?
-                    let dcx = DiagnosticCxBuilder::retag(
-                        &this.machine,
-                        retag_cause,
-                        new_tag,
-                        orig_tag,
-                        alloc_range(base_offset, size),
-                    );
-                    let mut dcx = dcx.build(&mut stacked_borrows.history, base_offset);
-                    dcx.log_creation();
-                    if protect.is_some() {
-                        dcx.log_protector();
-                    }
-                }
-                AllocKind::Function | AllocKind::VTable | AllocKind::Dead => {
-                    // No stacked borrows on these allocations.
-                }
-            }
-            Ok(())
-        };
-
-        if size == Size::ZERO {
-            trace!(
-                "reborrow of size 0: {} reference {:?} derived from {:?} (pointee {})",
-                kind,
-                new_tag,
-                place.ptr,
-                place.layout.ty,
-            );
-            // Don't update any stacks for a zero-sized access; borrow stacks are per-byte and this
-            // touches no bytes so there is no stack to put this tag in.
-            // However, if the pointer for this operation points at a real allocation we still
-            // record where it was created so that we can issue a helpful diagnostic if there is an
-            // attempt to use it for a non-zero-sized access.
-            // Dangling slices are a common case here; it's valid to get their length but with raw
-            // pointer tagging for example all calls to get_unchecked on them are invalid.
-            if let Ok((alloc_id, base_offset, orig_tag)) = this.ptr_try_get_alloc_id(place.ptr) {
-                log_creation(this, Some((alloc_id, base_offset, orig_tag)))?;
-                return Ok(Some(alloc_id));
-            }
-            // This pointer doesn't come with an AllocId. :shrug:
-            log_creation(this, None)?;
-            return Ok(None);
-        }
-
-        let (alloc_id, base_offset, orig_tag) = this.ptr_get_alloc_id(place.ptr)?;
-        log_creation(this, Some((alloc_id, base_offset, orig_tag)))?;
-
-        // Ensure we bail out if the pointer goes out-of-bounds (see miri#1050).
-        let (alloc_size, _) = this.get_live_alloc_size_and_align(alloc_id)?;
-        if base_offset + size > alloc_size {
-            throw_ub!(PointerOutOfBounds {
-                alloc_id,
-                alloc_size,
-                ptr_offset: this.machine_usize_to_isize(base_offset.bytes()),
-                ptr_size: size,
-                msg: CheckInAllocMsg::InboundsTest
-            });
-        }
-
-        trace!(
-            "reborrow: {} reference {:?} derived from {:?} (pointee {}): {:?}, size {}",
-            kind,
-            new_tag,
-            orig_tag,
-            place.layout.ty,
-            Pointer::new(alloc_id, base_offset),
-            size.bytes()
-        );
-
-        if let Some(protect) = protect {
-            // See comment in `Stack::item_invalidated` for why we store the tag twice.
-            this.frame_mut().extra.stacked_borrows.as_mut().unwrap().protected_tags.push(new_tag);
-            this.machine
-                .stacked_borrows
-                .as_mut()
-                .unwrap()
-                .get_mut()
-                .protected_tags
-                .insert(new_tag, protect);
-        }
-
-        // Update the stacks.
-        // Make sure that raw pointers and mutable shared references are reborrowed "weak":
-        // There could be existing unique pointers reborrowed from them that should remain valid!
-        let (perm, access) = match kind {
-            RefKind::Unique { two_phase } => {
-                // Permission is Unique only if the type is `Unpin` and this is not twophase
-                let perm = if !two_phase && place.layout.ty.is_unpin(*this.tcx, this.param_env()) {
-                    Permission::Unique
-                } else {
-                    Permission::SharedReadWrite
-                };
-                // We do an access for all full borrows, even if `!Unpin`.
-                let access = if !two_phase { Some(AccessKind::Write) } else { None };
-                (perm, access)
-            }
-            RefKind::Raw { mutable: true } => {
-                // Creating a raw ptr does not count as an access
-                (Permission::SharedReadWrite, None)
-            }
-            RefKind::Shared | RefKind::Raw { mutable: false } => {
-                // Shared references and *const are a whole different kind of game, the
-                // permission is not uniform across the entire range!
-                // We need a frozen-sensitive reborrow.
-                // We have to use shared references to alloc/memory_extra here since
-                // `visit_freeze_sensitive` needs to access the global state.
-                let alloc_extra = this.get_alloc_extra(alloc_id)?;
-                let mut stacked_borrows = alloc_extra
-                    .stacked_borrows
-                    .as_ref()
-                    .expect("we should have Stacked Borrows data")
-                    .borrow_mut();
-                this.visit_freeze_sensitive(place, size, |mut range, frozen| {
-                    // Adjust range.
-                    range.start += base_offset;
-                    // We are only ever `SharedReadOnly` inside the frozen bits.
-                    let (perm, access) = if frozen {
-                        (Permission::SharedReadOnly, Some(AccessKind::Read))
-                    } else {
-                        // Inside UnsafeCell, this does *not* count as an access, as there
-                        // might actually be mutable references further up the stack that
-                        // we have to keep alive.
-                        (Permission::SharedReadWrite, None)
-                    };
-                    let protected = if frozen {
-                        protect.is_some()
-                    } else {
-                        // We do not protect inside UnsafeCell.
-                        // This fixes https://github.com/rust-lang/rust/issues/55005.
-                        false
-                    };
-                    let item = Item::new(new_tag, perm, protected);
-                    let global = this.machine.stacked_borrows.as_ref().unwrap().borrow();
-                    let dcx = DiagnosticCxBuilder::retag(
-                        &this.machine,
-                        retag_cause,
-                        new_tag,
-                        orig_tag,
-                        alloc_range(base_offset, size),
-                    );
-                    stacked_borrows.for_each(range, dcx, |stack, dcx, exposed_tags| {
-                        stack.grant(orig_tag, item, access, &global, dcx, exposed_tags)
-                    })?;
-                    drop(global);
-                    if let Some(access) = access {
-                        assert_eq!(access, AccessKind::Read);
-                        // Make sure the data race model also knows about this.
-                        if let Some(data_race) = alloc_extra.data_race.as_ref() {
-                            data_race.read(alloc_id, range, &this.machine)?;
-                        }
-                    }
-                    Ok(())
-                })?;
-                return Ok(Some(alloc_id));
-            }
-        };
-
-        // Here we can avoid `borrow()` calls because we have mutable references.
-        // Note that this asserts that the allocation is mutable -- but since we are creating a
-        // mutable pointer, that seems reasonable.
-        let (alloc_extra, machine) = this.get_alloc_extra_mut(alloc_id)?;
-        let stacked_borrows = alloc_extra
-            .stacked_borrows
-            .as_mut()
-            .expect("we should have Stacked Borrows data")
-            .get_mut();
-        let item = Item::new(new_tag, perm, protect.is_some());
-        let range = alloc_range(base_offset, size);
-        let global = machine.stacked_borrows.as_ref().unwrap().borrow();
-        let dcx = DiagnosticCxBuilder::retag(
-            machine,
-            retag_cause,
-            new_tag,
-            orig_tag,
-            alloc_range(base_offset, size),
-        );
-        stacked_borrows.for_each(range, dcx, |stack, dcx, exposed_tags| {
-            stack.grant(orig_tag, item, access, &global, dcx, exposed_tags)
-        })?;
-        drop(global);
-        if let Some(access) = access {
-            assert_eq!(access, AccessKind::Write);
-            // Make sure the data race model also knows about this.
-            if let Some(data_race) = alloc_extra.data_race.as_mut() {
-                data_race.write(alloc_id, range, machine)?;
-            }
-        }
-
-        Ok(Some(alloc_id))
-    }
-
-    /// Retags an indidual pointer, returning the retagged version.
-    /// `mutbl` can be `None` to make this a raw pointer.
-    fn retag_reference(
-        &mut self,
-        val: &ImmTy<'tcx, Provenance>,
-        kind: RefKind,
-        retag_cause: RetagCause, // What caused this retag, for diagnostics only
-        protect: Option<ProtectorKind>,
-    ) -> InterpResult<'tcx, ImmTy<'tcx, Provenance>> {
-        let this = self.eval_context_mut();
-        // We want a place for where the ptr *points to*, so we get one.
-        let place = this.ref_to_mplace(val)?;
-        let size = this.size_and_align_of_mplace(&place)?.map(|(size, _)| size);
-        // FIXME: If we cannot determine the size (because the unsized tail is an `extern type`),
-        // bail out -- we cannot reasonably figure out which memory range to reborrow.
-        // See https://github.com/rust-lang/unsafe-code-guidelines/issues/276.
-        let size = match size {
-            Some(size) => size,
-            None => return Ok(val.clone()),
-        };
-
-        // Compute new borrow.
-        let new_tag = this.machine.stacked_borrows.as_mut().unwrap().get_mut().new_ptr();
-
-        // Reborrow.
-        let alloc_id = this.reborrow(&place, size, kind, retag_cause, new_tag, protect)?;
-
-        // Adjust pointer.
-        let new_place = place.map_provenance(|p| {
-            p.map(|prov| {
-                match alloc_id {
-                    Some(alloc_id) => {
-                        // If `reborrow` could figure out the AllocId of this ptr, hard-code it into the new one.
-                        // Even if we started out with a wildcard, this newly retagged pointer is tied to that allocation.
-                        Provenance::Concrete { alloc_id, sb: new_tag }
-                    }
-                    None => {
-                        // Looks like this has to stay a wildcard pointer.
-                        assert!(matches!(prov, Provenance::Wildcard));
-                        Provenance::Wildcard
-                    }
-                }
-            })
-        });
-
-        // Return new pointer.
-        Ok(ImmTy::from_immediate(new_place.to_ref(this), val.layout))
-    }
-}
-
-impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriInterpCx<'mir, 'tcx> {}
-pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
-    fn retag(&mut self, kind: RetagKind, place: &PlaceTy<'tcx, Provenance>) -> InterpResult<'tcx> {
-        let this = self.eval_context_mut();
-        let retag_fields = this.machine.stacked_borrows.as_mut().unwrap().get_mut().retag_fields;
-        let retag_cause = match kind {
-            RetagKind::TwoPhase { .. } => RetagCause::TwoPhase,
-            RetagKind::FnEntry => RetagCause::FnEntry,
-            RetagKind::Raw | RetagKind::Default => RetagCause::Normal,
-        };
-        let mut visitor = RetagVisitor { ecx: this, kind, retag_cause, retag_fields };
-        return visitor.visit_value(place);
-
-        // The actual visitor.
-        struct RetagVisitor<'ecx, 'mir, 'tcx> {
-            ecx: &'ecx mut MiriInterpCx<'mir, 'tcx>,
-            kind: RetagKind,
-            retag_cause: RetagCause,
-            retag_fields: RetagFields,
-        }
-        impl<'ecx, 'mir, 'tcx> RetagVisitor<'ecx, 'mir, 'tcx> {
-            #[inline(always)] // yes this helps in our benchmarks
-            fn retag_place(
-                &mut self,
-                place: &PlaceTy<'tcx, Provenance>,
-                ref_kind: RefKind,
-                retag_cause: RetagCause,
-                protector: Option<ProtectorKind>,
-            ) -> InterpResult<'tcx> {
-                let val = self.ecx.read_immediate(&self.ecx.place_to_op(place)?)?;
-                let val = self.ecx.retag_reference(&val, ref_kind, retag_cause, protector)?;
-                self.ecx.write_immediate(*val, place)?;
-                Ok(())
-            }
-        }
-        impl<'ecx, 'mir, 'tcx> MutValueVisitor<'mir, 'tcx, MiriMachine<'mir, 'tcx>>
-            for RetagVisitor<'ecx, 'mir, 'tcx>
-        {
-            type V = PlaceTy<'tcx, Provenance>;
-
-            #[inline(always)]
-            fn ecx(&mut self) -> &mut MiriInterpCx<'mir, 'tcx> {
-                self.ecx
-            }
-
-            fn visit_box(&mut self, place: &PlaceTy<'tcx, Provenance>) -> InterpResult<'tcx> {
-                // Boxes get a weak protectors, since they may be deallocated.
-                self.retag_place(
-                    place,
-                    RefKind::Unique { two_phase: false },
-                    self.retag_cause,
-                    /*protector*/
-                    (self.kind == RetagKind::FnEntry).then_some(ProtectorKind::WeakProtector),
-                )
-            }
-
-            fn visit_value(&mut self, place: &PlaceTy<'tcx, Provenance>) -> InterpResult<'tcx> {
-                // If this place is smaller than a pointer, we know that it can't contain any
-                // pointers we need to retag, so we can stop recursion early.
-                // This optimization is crucial for ZSTs, because they can contain way more fields
-                // than we can ever visit.
-                if place.layout.is_sized() && place.layout.size < self.ecx.pointer_size() {
-                    return Ok(());
-                }
-
-                // Check the type of this value to see what to do with it (retag, or recurse).
-                match place.layout.ty.kind() {
-                    ty::Ref(_, _, mutbl) => {
-                        let ref_kind = match mutbl {
-                            Mutability::Mut =>
-                                RefKind::Unique { two_phase: self.kind == RetagKind::TwoPhase },
-                            Mutability::Not => RefKind::Shared,
-                        };
-                        self.retag_place(
-                            place,
-                            ref_kind,
-                            self.retag_cause,
-                            /*protector*/
-                            (self.kind == RetagKind::FnEntry)
-                                .then_some(ProtectorKind::StrongProtector),
-                        )?;
-                    }
-                    ty::RawPtr(tym) => {
-                        // We definitely do *not* want to recurse into raw pointers -- wide raw
-                        // pointers have fields, and for dyn Trait pointees those can have reference
-                        // type!
-                        if self.kind == RetagKind::Raw {
-                            // Raw pointers need to be enabled.
-                            self.retag_place(
-                                place,
-                                RefKind::Raw { mutable: tym.mutbl == Mutability::Mut },
-                                self.retag_cause,
-                                /*protector*/ None,
-                            )?;
-                        }
-                    }
-                    _ if place.layout.ty.ty_adt_def().is_some_and(|adt| adt.is_box()) => {
-                        // Recurse for boxes, they require some tricky handling and will end up in `visit_box` above.
-                        // (Yes this means we technically also recursively retag the allocator itself
-                        // even if field retagging is not enabled. *shrug*)
-                        self.walk_value(place)?;
-                    }
-                    _ => {
-                        // Not a reference/pointer/box. Only recurse if configured appropriately.
-                        let recurse = match self.retag_fields {
-                            RetagFields::No => false,
-                            RetagFields::Yes => true,
-                            RetagFields::OnlyScalar => {
-                                // Matching `ArgAbi::new` at the time of writing, only fields of
-                                // `Scalar` and `ScalarPair` ABI are considered.
-                                matches!(place.layout.abi, Abi::Scalar(..) | Abi::ScalarPair(..))
-                            }
-                        };
-                        if recurse {
-                            self.walk_value(place)?;
-                        }
-                    }
-                }
-
-                Ok(())
-            }
-        }
-    }
-
-    /// After a stack frame got pushed, retag the return place so that we are sure
-    /// it does not alias with anything.
-    ///
-    /// This is a HACK because there is nothing in MIR that would make the retag
-    /// explicit. Also see <https://github.com/rust-lang/rust/issues/71117>.
-    fn retag_return_place(&mut self) -> InterpResult<'tcx> {
-        let this = self.eval_context_mut();
-        let return_place = &this.frame().return_place;
-        if return_place.layout.is_zst() {
-            // There may not be any memory here, nothing to do.
-            return Ok(());
-        }
-        // We need this to be in-memory to use tagged pointers.
-        let return_place = this.force_allocation(&return_place.clone())?;
-
-        // We have to turn the place into a pointer to use the existing code.
-        // (The pointer type does not matter, so we use a raw pointer.)
-        let ptr_layout = this.layout_of(this.tcx.mk_mut_ptr(return_place.layout.ty))?;
-        let val = ImmTy::from_immediate(return_place.to_ref(this), ptr_layout);
-        // Reborrow it. With protection! That is part of the point.
-        let val = this.retag_reference(
-            &val,
-            RefKind::Unique { two_phase: false },
-            RetagCause::FnReturn,
-            /*protector*/ Some(ProtectorKind::StrongProtector),
-        )?;
-        // And use reborrowed pointer for return place.
-        let return_place = this.ref_to_mplace(&val)?;
-        this.frame_mut().return_place = return_place.into();
-
-        Ok(())
-    }
-
-    /// Mark the given tag as exposed. It was found on a pointer with the given AllocId.
-    fn expose_tag(&mut self, alloc_id: AllocId, tag: SbTag) -> InterpResult<'tcx> {
-        let this = self.eval_context_mut();
-
-        // Function pointers and dead objects don't have an alloc_extra so we ignore them.
-        // This is okay because accessing them is UB anyway, no need for any Stacked Borrows checks.
-        // NOT using `get_alloc_extra_mut` since this might be a read-only allocation!
-        let (_size, _align, kind) = this.get_alloc_info(alloc_id);
-        match kind {
-            AllocKind::LiveData => {
-                // This should have alloc_extra data, but `get_alloc_extra` can still fail
-                // if converting this alloc_id from a global to a local one
-                // uncovers a non-supported `extern static`.
-                let alloc_extra = this.get_alloc_extra(alloc_id)?;
-                trace!("Stacked Borrows tag {tag:?} exposed in {alloc_id:?}");
-                alloc_extra.stacked_borrows.as_ref().unwrap().borrow_mut().exposed_tags.insert(tag);
-            }
-            AllocKind::Function | AllocKind::VTable | AllocKind::Dead => {
-                // No stacked borrows on these allocations.
-            }
-        }
-        Ok(())
-    }
-
-    fn print_stacks(&mut self, alloc_id: AllocId) -> InterpResult<'tcx> {
-        let this = self.eval_context_mut();
-        let alloc_extra = this.get_alloc_extra(alloc_id)?;
-        let stacks = alloc_extra.stacked_borrows.as_ref().unwrap().borrow();
-        for (range, stack) in stacks.stacks.iter_all() {
-            print!("{range:?}: [");
-            if let Some(bottom) = stack.unknown_bottom() {
-                print!(" unknown-bottom(..{bottom:?})");
-            }
-            for i in 0..stack.len() {
-                let item = stack.get(i).unwrap();
-                print!(" {:?}{:?}", item.perm(), item.tag());
-            }
-            println!(" ]");
-        }
-        Ok(())
-    }
-}
diff --git a/src/tools/miri/src/stacked_borrows/stack.rs b/src/tools/miri/src/stacked_borrows/stack.rs
deleted file mode 100644 (file)
index 51a6fba..0000000
+++ /dev/null
@@ -1,469 +0,0 @@
-#[cfg(feature = "stack-cache")]
-use std::ops::Range;
-
-use rustc_data_structures::fx::FxHashSet;
-
-use crate::stacked_borrows::{AccessKind, Item, Permission, SbTag};
-use crate::ProvenanceExtra;
-
-/// Exactly what cache size we should use is a difficult tradeoff. There will always be some
-/// workload which has a `SbTag` working set which exceeds the size of the cache, and ends up
-/// falling back to linear searches of the borrow stack very often.
-/// The cost of making this value too large is that the loop in `Stack::insert` which ensures the
-/// entries in the cache stay correct after an insert becomes expensive.
-#[cfg(feature = "stack-cache")]
-const CACHE_LEN: usize = 32;
-
-/// Extra per-location state.
-#[derive(Clone, Debug)]
-pub struct Stack {
-    /// Used *mostly* as a stack; never empty.
-    /// Invariants:
-    /// * Above a `SharedReadOnly` there can only be more `SharedReadOnly`.
-    /// * Except for `Untagged`, no tag occurs in the stack more than once.
-    borrows: Vec<Item>,
-    /// If this is `Some(id)`, then the actual current stack is unknown. This can happen when
-    /// wildcard pointers are used to access this location. What we do know is that `borrows` are at
-    /// the top of the stack, and below it are arbitrarily many items whose `tag` is strictly less
-    /// than `id`.
-    /// When the bottom is unknown, `borrows` always has a `SharedReadOnly` or `Unique` at the bottom;
-    /// we never have the unknown-to-known boundary in an SRW group.
-    unknown_bottom: Option<SbTag>,
-
-    /// A small LRU cache of searches of the borrow stack.
-    #[cfg(feature = "stack-cache")]
-    cache: StackCache,
-    /// On a read, we need to disable all `Unique` above the granting item. We can avoid most of
-    /// this scan by keeping track of the region of the borrow stack that may contain `Unique`s.
-    #[cfg(feature = "stack-cache")]
-    unique_range: Range<usize>,
-}
-
-impl Stack {
-    pub fn retain(&mut self, tags: &FxHashSet<SbTag>) {
-        let mut first_removed = None;
-
-        // We never consider removing the bottom-most tag. For stacks without an unknown
-        // bottom this preserves the base tag.
-        // Note that the algorithm below is based on considering the tag at read_idx - 1,
-        // so precisely considering the tag at index 0 for removal when we have an unknown
-        // bottom would complicate the implementation. The simplification of not considering
-        // it does not have a significant impact on the degree to which the GC mititages
-        // memory growth.
-        let mut read_idx = 1;
-        let mut write_idx = read_idx;
-        while read_idx < self.borrows.len() {
-            let left = self.borrows[read_idx - 1];
-            let this = self.borrows[read_idx];
-            let should_keep = match this.perm() {
-                // SharedReadWrite is the simplest case, if it's unreachable we can just remove it.
-                Permission::SharedReadWrite => tags.contains(&this.tag()),
-                // Only retain a Disabled tag if it is terminating a SharedReadWrite block.
-                Permission::Disabled => left.perm() == Permission::SharedReadWrite,
-                // Unique and SharedReadOnly can terminate a SharedReadWrite block, so only remove
-                // them if they are both unreachable and not directly after a SharedReadWrite.
-                Permission::Unique | Permission::SharedReadOnly =>
-                    left.perm() == Permission::SharedReadWrite || tags.contains(&this.tag()),
-            };
-
-            if should_keep {
-                if read_idx != write_idx {
-                    self.borrows[write_idx] = self.borrows[read_idx];
-                }
-                write_idx += 1;
-            } else if first_removed.is_none() {
-                first_removed = Some(read_idx);
-            }
-
-            read_idx += 1;
-        }
-        self.borrows.truncate(write_idx);
-
-        #[cfg(not(feature = "stack-cache"))]
-        drop(first_removed); // This is only needed for the stack-cache
-
-        #[cfg(feature = "stack-cache")]
-        if let Some(first_removed) = first_removed {
-            // Either end of unique_range may have shifted, all we really know is that we can't
-            // have introduced a new Unique.
-            if !self.unique_range.is_empty() {
-                self.unique_range = 0..self.len();
-            }
-
-            // Replace any Items which have been collected with the base item, a known-good value.
-            for i in 0..CACHE_LEN {
-                if self.cache.idx[i] >= first_removed {
-                    self.cache.items[i] = self.borrows[0];
-                    self.cache.idx[i] = 0;
-                }
-            }
-        }
-    }
-}
-
-/// A very small cache of searches of a borrow stack, mapping `Item`s to their position in said stack.
-///
-/// It may seem like maintaining this cache is a waste for small stacks, but
-/// (a) iterating over small fixed-size arrays is super fast, and (b) empirically this helps *a lot*,
-/// probably because runtime is dominated by large stacks.
-#[cfg(feature = "stack-cache")]
-#[derive(Clone, Debug)]
-struct StackCache {
-    items: [Item; CACHE_LEN], // Hot in find_granting
-    idx: [usize; CACHE_LEN],  // Hot in grant
-}
-
-#[cfg(feature = "stack-cache")]
-impl StackCache {
-    /// When a tag is used, we call this function to add or refresh it in the cache.
-    ///
-    /// We use the position in the cache to represent how recently a tag was used; the first position
-    /// is the most recently used tag. So an add shifts every element towards the end, and inserts
-    /// the new element at the start. We lose the last element.
-    /// This strategy is effective at keeping the most-accessed items in the cache, but it costs a
-    /// linear shift across the entire cache when we add a new tag.
-    fn add(&mut self, idx: usize, item: Item) {
-        self.items.copy_within(0..CACHE_LEN - 1, 1);
-        self.items[0] = item;
-        self.idx.copy_within(0..CACHE_LEN - 1, 1);
-        self.idx[0] = idx;
-    }
-}
-
-impl PartialEq for Stack {
-    fn eq(&self, other: &Self) -> bool {
-        // All the semantics of Stack are in self.borrows, everything else is caching
-        self.borrows == other.borrows
-    }
-}
-
-impl Eq for Stack {}
-
-impl<'tcx> Stack {
-    /// Panics if any of the caching mechanisms have broken,
-    /// - The StackCache indices don't refer to the parallel items,
-    /// - There are no Unique items outside of first_unique..last_unique
-    #[cfg(all(feature = "stack-cache", debug_assertions))]
-    fn verify_cache_consistency(&self) {
-        // Only a full cache needs to be valid. Also see the comments in find_granting_cache
-        // and set_unknown_bottom.
-        if self.borrows.len() >= CACHE_LEN {
-            for (tag, stack_idx) in self.cache.items.iter().zip(self.cache.idx.iter()) {
-                assert_eq!(self.borrows[*stack_idx], *tag);
-            }
-        }
-
-        // Check that all Unique items fall within unique_range.
-        for (idx, item) in self.borrows.iter().enumerate() {
-            if item.perm() == Permission::Unique {
-                assert!(
-                    self.unique_range.contains(&idx),
-                    "{:?} {:?}",
-                    self.unique_range,
-                    self.borrows
-                );
-            }
-        }
-
-        // Check that the unique_range is a valid index into the borrow stack.
-        // This asserts that the unique_range's start <= end.
-        let _uniques = &self.borrows[self.unique_range.clone()];
-
-        // We cannot assert that the unique range is precise.
-        // Both ends may shift around when `Stack::retain` is called. Additionally,
-        // when we pop items within the unique range, setting the end of the range precisely
-        // requires doing a linear search of the borrow stack, which is exactly the kind of
-        // operation that all this caching exists to avoid.
-    }
-
-    /// Find the item granting the given kind of access to the given tag, and return where
-    /// it is on the stack. For wildcard tags, the given index is approximate, but if *no*
-    /// index is given it means the match was *not* in the known part of the stack.
-    /// `Ok(None)` indicates it matched the "unknown" part of the stack.
-    /// `Err` indicates it was not found.
-    pub(super) fn find_granting(
-        &mut self,
-        access: AccessKind,
-        tag: ProvenanceExtra,
-        exposed_tags: &FxHashSet<SbTag>,
-    ) -> Result<Option<usize>, ()> {
-        #[cfg(all(feature = "stack-cache", debug_assertions))]
-        self.verify_cache_consistency();
-
-        let ProvenanceExtra::Concrete(tag) = tag else {
-            // Handle the wildcard case.
-            // Go search the stack for an exposed tag.
-            if let Some(idx) =
-                self.borrows
-                    .iter()
-                    .enumerate() // we also need to know *where* in the stack
-                    .rev() // search top-to-bottom
-                    .find_map(|(idx, item)| {
-                        // If the item fits and *might* be this wildcard, use it.
-                        if item.perm().grants(access) && exposed_tags.contains(&item.tag()) {
-                            Some(idx)
-                        } else {
-                            None
-                        }
-                    })
-            {
-                return Ok(Some(idx));
-            }
-            // If we couldn't find it in the stack, check the unknown bottom.
-            return if self.unknown_bottom.is_some() { Ok(None) } else { Err(()) };
-        };
-
-        if let Some(idx) = self.find_granting_tagged(access, tag) {
-            return Ok(Some(idx));
-        }
-
-        // Couldn't find it in the stack; but if there is an unknown bottom it might be there.
-        let found = self.unknown_bottom.is_some_and(|unknown_limit| {
-            tag.0 < unknown_limit.0 // unknown_limit is an upper bound for what can be in the unknown bottom.
-        });
-        if found { Ok(None) } else { Err(()) }
-    }
-
-    fn find_granting_tagged(&mut self, access: AccessKind, tag: SbTag) -> Option<usize> {
-        #[cfg(feature = "stack-cache")]
-        if let Some(idx) = self.find_granting_cache(access, tag) {
-            return Some(idx);
-        }
-
-        // If we didn't find the tag in the cache, fall back to a linear search of the
-        // whole stack, and add the tag to the cache.
-        for (stack_idx, item) in self.borrows.iter().enumerate().rev() {
-            if tag == item.tag() && item.perm().grants(access) {
-                #[cfg(feature = "stack-cache")]
-                self.cache.add(stack_idx, *item);
-                return Some(stack_idx);
-            }
-        }
-        None
-    }
-
-    #[cfg(feature = "stack-cache")]
-    fn find_granting_cache(&mut self, access: AccessKind, tag: SbTag) -> Option<usize> {
-        // This looks like a common-sense optimization; we're going to do a linear search of the
-        // cache or the borrow stack to scan the shorter of the two. This optimization is miniscule
-        // and this check actually ensures we do not access an invalid cache.
-        // When a stack is created and when items are removed from the top of the borrow stack, we
-        // need some valid value to populate the cache. In both cases, we try to use the bottom
-        // item. But when the stack is cleared in `set_unknown_bottom` there is nothing we could
-        // place in the cache that is correct. But due to the way we populate the cache in
-        // `StackCache::add`, we know that when the borrow stack has grown larger than the cache,
-        // every slot in the cache is valid.
-        if self.borrows.len() <= CACHE_LEN {
-            return None;
-        }
-        // Search the cache for the tag we're looking up
-        let cache_idx = self.cache.items.iter().position(|t| t.tag() == tag)?;
-        let stack_idx = self.cache.idx[cache_idx];
-        // If we found the tag, look up its position in the stack to see if it grants
-        // the required permission
-        if self.cache.items[cache_idx].perm().grants(access) {
-            // If it does, and it's not already in the most-recently-used position, re-insert it at
-            // the most-recently-used position. This technically reduces the efficiency of the
-            // cache by duplicating elements, but current benchmarks do not seem to benefit from
-            // avoiding this duplication.
-            // But if the tag is in position 1, avoiding the duplicating add is trivial.
-            // If it does, and it's not already in the most-recently-used position, move it there.
-            // Except if the tag is in position 1, this is equivalent to just a swap, so do that.
-            if cache_idx == 1 {
-                self.cache.items.swap(0, 1);
-                self.cache.idx.swap(0, 1);
-            } else if cache_idx > 1 {
-                self.cache.add(stack_idx, self.cache.items[cache_idx]);
-            }
-            Some(stack_idx)
-        } else {
-            // Tag is in the cache, but it doesn't grant the required permission
-            None
-        }
-    }
-
-    pub fn insert(&mut self, new_idx: usize, new: Item) {
-        self.borrows.insert(new_idx, new);
-
-        #[cfg(feature = "stack-cache")]
-        self.insert_cache(new_idx, new);
-    }
-
-    #[cfg(feature = "stack-cache")]
-    fn insert_cache(&mut self, new_idx: usize, new: Item) {
-        // Adjust the possibly-unique range if an insert occurs before or within it
-        if self.unique_range.start >= new_idx {
-            self.unique_range.start += 1;
-        }
-        if self.unique_range.end >= new_idx {
-            self.unique_range.end += 1;
-        }
-        if new.perm() == Permission::Unique {
-            // If this is the only Unique, set the range to contain just the new item.
-            if self.unique_range.is_empty() {
-                self.unique_range = new_idx..new_idx + 1;
-            } else {
-                // We already have other Unique items, expand the range to include the new item
-                self.unique_range.start = self.unique_range.start.min(new_idx);
-                self.unique_range.end = self.unique_range.end.max(new_idx + 1);
-            }
-        }
-
-        // The above insert changes the meaning of every index in the cache >= new_idx, so now
-        // we need to find every one of those indexes and increment it.
-        // But if the insert is at the end (equivalent to a push), we can skip this step because
-        // it didn't change the position of any other items.
-        if new_idx != self.borrows.len() - 1 {
-            for idx in &mut self.cache.idx {
-                if *idx >= new_idx {
-                    *idx += 1;
-                }
-            }
-        }
-
-        // This primes the cache for the next access, which is almost always the just-added tag.
-        self.cache.add(new_idx, new);
-
-        #[cfg(debug_assertions)]
-        self.verify_cache_consistency();
-    }
-
-    /// Construct a new `Stack` using the passed `Item` as the base tag.
-    pub fn new(item: Item) -> Self {
-        Stack {
-            borrows: vec![item],
-            unknown_bottom: None,
-            #[cfg(feature = "stack-cache")]
-            cache: StackCache { idx: [0; CACHE_LEN], items: [item; CACHE_LEN] },
-            #[cfg(feature = "stack-cache")]
-            unique_range: if item.perm() == Permission::Unique { 0..1 } else { 0..0 },
-        }
-    }
-
-    pub fn get(&self, idx: usize) -> Option<Item> {
-        self.borrows.get(idx).cloned()
-    }
-
-    #[allow(clippy::len_without_is_empty)] // Stacks are never empty
-    pub fn len(&self) -> usize {
-        self.borrows.len()
-    }
-
-    pub fn unknown_bottom(&self) -> Option<SbTag> {
-        self.unknown_bottom
-    }
-
-    pub fn set_unknown_bottom(&mut self, tag: SbTag) {
-        // We clear the borrow stack but the lookup cache doesn't support clearing per se. Instead,
-        // there is a check explained in `find_granting_cache` which protects against accessing the
-        // cache when it has been cleared and not yet refilled.
-        self.borrows.clear();
-        self.unknown_bottom = Some(tag);
-        #[cfg(feature = "stack-cache")]
-        {
-            self.unique_range = 0..0;
-        }
-    }
-
-    /// Find all `Unique` elements in this borrow stack above `granting_idx`, pass a copy of them
-    /// to the `visitor`, then set their `Permission` to `Disabled`.
-    pub fn disable_uniques_starting_at(
-        &mut self,
-        disable_start: usize,
-        mut visitor: impl FnMut(Item) -> crate::InterpResult<'tcx>,
-    ) -> crate::InterpResult<'tcx> {
-        #[cfg(feature = "stack-cache")]
-        let unique_range = self.unique_range.clone();
-        #[cfg(not(feature = "stack-cache"))]
-        let unique_range = 0..self.len();
-
-        if disable_start <= unique_range.end {
-            let lower = unique_range.start.max(disable_start);
-            let upper = unique_range.end;
-            for item in &mut self.borrows[lower..upper] {
-                if item.perm() == Permission::Unique {
-                    log::trace!("access: disabling item {:?}", item);
-                    visitor(*item)?;
-                    item.set_permission(Permission::Disabled);
-                    // Also update all copies of this item in the cache.
-                    #[cfg(feature = "stack-cache")]
-                    for it in &mut self.cache.items {
-                        if it.tag() == item.tag() {
-                            it.set_permission(Permission::Disabled);
-                        }
-                    }
-                }
-            }
-        }
-
-        #[cfg(feature = "stack-cache")]
-        if disable_start <= self.unique_range.start {
-            // We disabled all Unique items
-            self.unique_range.start = 0;
-            self.unique_range.end = 0;
-        } else {
-            // Truncate the range to only include items up to the index that we started disabling
-            // at.
-            self.unique_range.end = self.unique_range.end.min(disable_start);
-        }
-
-        #[cfg(all(feature = "stack-cache", debug_assertions))]
-        self.verify_cache_consistency();
-
-        Ok(())
-    }
-
-    /// Produces an iterator which iterates over `range` in reverse, and when dropped removes that
-    /// range of `Item`s from this `Stack`.
-    pub fn pop_items_after<V: FnMut(Item) -> crate::InterpResult<'tcx>>(
-        &mut self,
-        start: usize,
-        mut visitor: V,
-    ) -> crate::InterpResult<'tcx> {
-        while self.borrows.len() > start {
-            let item = self.borrows.pop().unwrap();
-            visitor(item)?;
-        }
-
-        #[cfg(feature = "stack-cache")]
-        if !self.borrows.is_empty() {
-            // After we remove from the borrow stack, every aspect of our caching may be invalid, but it is
-            // also possible that the whole cache is still valid. So we call this method to repair what
-            // aspects of the cache are now invalid, instead of resetting the whole thing to a trivially
-            // valid default state.
-            let base_tag = self.borrows[0];
-            let mut removed = 0;
-            let mut cursor = 0;
-            // Remove invalid entries from the cache by rotating them to the end of the cache, then
-            // keep track of how many invalid elements there are and overwrite them with the base tag.
-            // The base tag here serves as a harmless default value.
-            for _ in 0..CACHE_LEN - 1 {
-                if self.cache.idx[cursor] >= start {
-                    self.cache.idx[cursor..CACHE_LEN - removed].rotate_left(1);
-                    self.cache.items[cursor..CACHE_LEN - removed].rotate_left(1);
-                    removed += 1;
-                } else {
-                    cursor += 1;
-                }
-            }
-            for i in CACHE_LEN - removed - 1..CACHE_LEN {
-                self.cache.idx[i] = 0;
-                self.cache.items[i] = base_tag;
-            }
-
-            if start <= self.unique_range.start {
-                // We removed all the Unique items
-                self.unique_range = 0..0;
-            } else {
-                // Ensure the range doesn't extend past the new top of the stack
-                self.unique_range.end = self.unique_range.end.min(start);
-            }
-        } else {
-            self.unique_range = 0..0;
-        }
-
-        #[cfg(all(feature = "stack-cache", debug_assertions))]
-        self.verify_cache_consistency();
-        Ok(())
-    }
-}
index 73712348f0d5f076cd3d81e662ecc112cafad175..c1194fe22163a65cbe8977e849e73161dcc0c48c 100644 (file)
@@ -3,11 +3,11 @@
 use crate::*;
 
 pub trait VisitTags {
-    fn visit_tags(&self, visit: &mut dyn FnMut(SbTag));
+    fn visit_tags(&self, visit: &mut dyn FnMut(BorTag));
 }
 
 impl<T: VisitTags> VisitTags for Option<T> {
-    fn visit_tags(&self, visit: &mut dyn FnMut(SbTag)) {
+    fn visit_tags(&self, visit: &mut dyn FnMut(BorTag)) {
         if let Some(x) = self {
             x.visit_tags(visit);
         }
@@ -15,41 +15,41 @@ fn visit_tags(&self, visit: &mut dyn FnMut(SbTag)) {
 }
 
 impl<T: VisitTags> VisitTags for std::cell::RefCell<T> {
-    fn visit_tags(&self, visit: &mut dyn FnMut(SbTag)) {
+    fn visit_tags(&self, visit: &mut dyn FnMut(BorTag)) {
         self.borrow().visit_tags(visit)
     }
 }
 
-impl VisitTags for SbTag {
-    fn visit_tags(&self, visit: &mut dyn FnMut(SbTag)) {
+impl VisitTags for BorTag {
+    fn visit_tags(&self, visit: &mut dyn FnMut(BorTag)) {
         visit(*self)
     }
 }
 
 impl VisitTags for Provenance {
-    fn visit_tags(&self, visit: &mut dyn FnMut(SbTag)) {
-        if let Provenance::Concrete { sb, .. } = self {
-            visit(*sb);
+    fn visit_tags(&self, visit: &mut dyn FnMut(BorTag)) {
+        if let Provenance::Concrete { tag, .. } = self {
+            visit(*tag);
         }
     }
 }
 
 impl VisitTags for Pointer<Provenance> {
-    fn visit_tags(&self, visit: &mut dyn FnMut(SbTag)) {
+    fn visit_tags(&self, visit: &mut dyn FnMut(BorTag)) {
         let (prov, _offset) = self.into_parts();
         prov.visit_tags(visit);
     }
 }
 
 impl VisitTags for Pointer<Option<Provenance>> {
-    fn visit_tags(&self, visit: &mut dyn FnMut(SbTag)) {
+    fn visit_tags(&self, visit: &mut dyn FnMut(BorTag)) {
         let (prov, _offset) = self.into_parts();
         prov.visit_tags(visit);
     }
 }
 
 impl VisitTags for Scalar<Provenance> {
-    fn visit_tags(&self, visit: &mut dyn FnMut(SbTag)) {
+    fn visit_tags(&self, visit: &mut dyn FnMut(BorTag)) {
         match self {
             Scalar::Ptr(ptr, _) => ptr.visit_tags(visit),
             Scalar::Int(_) => (),
@@ -58,7 +58,7 @@ fn visit_tags(&self, visit: &mut dyn FnMut(SbTag)) {
 }
 
 impl VisitTags for Immediate<Provenance> {
-    fn visit_tags(&self, visit: &mut dyn FnMut(SbTag)) {
+    fn visit_tags(&self, visit: &mut dyn FnMut(BorTag)) {
         match self {
             Immediate::Scalar(s) => {
                 s.visit_tags(visit);
@@ -73,7 +73,7 @@ fn visit_tags(&self, visit: &mut dyn FnMut(SbTag)) {
 }
 
 impl VisitTags for MemPlaceMeta<Provenance> {
-    fn visit_tags(&self, visit: &mut dyn FnMut(SbTag)) {
+    fn visit_tags(&self, visit: &mut dyn FnMut(BorTag)) {
         match self {
             MemPlaceMeta::Meta(m) => m.visit_tags(visit),
             MemPlaceMeta::None => {}
@@ -82,7 +82,7 @@ fn visit_tags(&self, visit: &mut dyn FnMut(SbTag)) {
 }
 
 impl VisitTags for MemPlace<Provenance> {
-    fn visit_tags(&self, visit: &mut dyn FnMut(SbTag)) {
+    fn visit_tags(&self, visit: &mut dyn FnMut(BorTag)) {
         let MemPlace { ptr, meta } = self;
         ptr.visit_tags(visit);
         meta.visit_tags(visit);
@@ -90,13 +90,13 @@ fn visit_tags(&self, visit: &mut dyn FnMut(SbTag)) {
 }
 
 impl VisitTags for MPlaceTy<'_, Provenance> {
-    fn visit_tags(&self, visit: &mut dyn FnMut(SbTag)) {
+    fn visit_tags(&self, visit: &mut dyn FnMut(BorTag)) {
         (**self).visit_tags(visit)
     }
 }
 
 impl VisitTags for Place<Provenance> {
-    fn visit_tags(&self, visit: &mut dyn FnMut(SbTag)) {
+    fn visit_tags(&self, visit: &mut dyn FnMut(BorTag)) {
         match self {
             Place::Ptr(p) => p.visit_tags(visit),
             Place::Local { .. } => {
@@ -107,13 +107,13 @@ fn visit_tags(&self, visit: &mut dyn FnMut(SbTag)) {
 }
 
 impl VisitTags for PlaceTy<'_, Provenance> {
-    fn visit_tags(&self, visit: &mut dyn FnMut(SbTag)) {
+    fn visit_tags(&self, visit: &mut dyn FnMut(BorTag)) {
         (**self).visit_tags(visit)
     }
 }
 
 impl VisitTags for Operand<Provenance> {
-    fn visit_tags(&self, visit: &mut dyn FnMut(SbTag)) {
+    fn visit_tags(&self, visit: &mut dyn FnMut(BorTag)) {
         match self {
             Operand::Immediate(imm) => {
                 imm.visit_tags(visit);
@@ -126,7 +126,7 @@ fn visit_tags(&self, visit: &mut dyn FnMut(SbTag)) {
 }
 
 impl VisitTags for Allocation<Provenance, AllocExtra> {
-    fn visit_tags(&self, visit: &mut dyn FnMut(SbTag)) {
+    fn visit_tags(&self, visit: &mut dyn FnMut(BorTag)) {
         for prov in self.provenance().provenances() {
             prov.visit_tags(visit);
         }
@@ -136,7 +136,7 @@ fn visit_tags(&self, visit: &mut dyn FnMut(SbTag)) {
 }
 
 impl VisitTags for crate::MiriInterpCx<'_, '_> {
-    fn visit_tags(&self, visit: &mut dyn FnMut(SbTag)) {
+    fn visit_tags(&self, visit: &mut dyn FnMut(BorTag)) {
         // Memory.
         self.memory.alloc_map().iter(|it| {
             for (_id, (_kind, alloc)) in it {
@@ -154,7 +154,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriInterpCxExt<'mir, 'tcx> {
     fn garbage_collect_tags(&mut self) -> InterpResult<'tcx> {
         let this = self.eval_context_mut();
         // No reason to do anything at all if stacked borrows is off.
-        if this.machine.stacked_borrows.is_none() {
+        if this.machine.borrow_tracker.is_none() {
             return Ok(());
         }
 
@@ -167,17 +167,13 @@ fn garbage_collect_tags(&mut self) -> InterpResult<'tcx> {
         Ok(())
     }
 
-    fn remove_unreachable_tags(&mut self, tags: FxHashSet<SbTag>) {
+    fn remove_unreachable_tags(&mut self, tags: FxHashSet<BorTag>) {
         let this = self.eval_context_mut();
         this.memory.alloc_map().iter(|it| {
             for (_id, (_kind, alloc)) in it {
-                alloc
-                    .extra
-                    .stacked_borrows
-                    .as_ref()
-                    .unwrap()
-                    .borrow_mut()
-                    .remove_unreachable_tags(&tags);
+                if let Some(bt) = &alloc.extra.borrow_tracker {
+                    bt.remove_unreachable_tags(&tags);
+                }
             }
         });
     }
index ec9ce76685b5572e6c43d3e4dad1fb10c552c751..2d3275f6b19011eda917967475e5cf9d3c77cc1c 100644 (file)
@@ -10,7 +10,7 @@ LL | | }
    | |_^ the program aborted execution
    |
    = note: inside `panic_abort` at $DIR/abort-terminator.rs:LL:CC
-note: inside `main` at $DIR/abort-terminator.rs:LL:CC
+note: inside `main`
   --> $DIR/abort-terminator.rs:LL:CC
    |
 LL |     panic_abort();
index 28439b54b2908270a7ffbf3f8c022d9b49aab4a6..095eeeb79de7b2d4e58ec72f945f85fbee7d4cd5 100644 (file)
@@ -8,7 +8,7 @@ LL |     unsafe { __rust_dealloc(ptr, layout.size(), layout.align()) }
    = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
    = note: BACKTRACE:
    = note: inside `std::alloc::dealloc` at RUSTLIB/alloc/src/alloc.rs:LL:CC
-note: inside `main` at $DIR/deallocate-bad-alignment.rs:LL:CC
+note: inside `main`
   --> $DIR/deallocate-bad-alignment.rs:LL:CC
    |
 LL |         dealloc(x, Layout::from_size_align_unchecked(1, 2));
index a6ceab1f56f513d742e5a5055a25a7000de269e3..5fe93c841b22c80c963456a3f77fe230a29ee89b 100644 (file)
@@ -8,7 +8,7 @@ LL |     unsafe { __rust_dealloc(ptr, layout.size(), layout.align()) }
    = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
    = note: BACKTRACE:
    = note: inside `std::alloc::dealloc` at RUSTLIB/alloc/src/alloc.rs:LL:CC
-note: inside `main` at $DIR/deallocate-bad-size.rs:LL:CC
+note: inside `main`
   --> $DIR/deallocate-bad-size.rs:LL:CC
    |
 LL |         dealloc(x, Layout::from_size_align_unchecked(2, 1));
index b6c5b6f97ee7b9fa9a7bb8f08bc8c492270b9b75..fa7a74ee13cfe64cb12d27181463715ef1c92767 100644 (file)
@@ -8,7 +8,7 @@ LL |     unsafe { __rust_dealloc(ptr, layout.size(), layout.align()) }
    = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
    = note: BACKTRACE:
    = note: inside `std::alloc::dealloc` at RUSTLIB/alloc/src/alloc.rs:LL:CC
-note: inside `main` at $DIR/deallocate-twice.rs:LL:CC
+note: inside `main`
   --> $DIR/deallocate-twice.rs:LL:CC
    |
 LL |         dealloc(x, Layout::from_size_align_unchecked(1, 1));
index 4ee85add6c228242c656d0bd1f2a361107fe771b..62ffb8142a3fb36c971153894af5f7734c4cbd8f 100644 (file)
@@ -9,7 +9,7 @@ LL |         FREE();
    = note: BACKTRACE:
    = note: inside `std::sys::PLATFORM::alloc::<impl std::alloc::GlobalAlloc for std::alloc::System>::dealloc` at RUSTLIB/std/src/sys/PLATFORM/alloc.rs:LL:CC
    = note: inside `<std::alloc::System as std::alloc::Allocator>::deallocate` at RUSTLIB/std/src/alloc.rs:LL:CC
-note: inside `main` at $DIR/global_system_mixup.rs:LL:CC
+note: inside `main`
   --> $DIR/global_system_mixup.rs:LL:CC
    |
 LL |         System.deallocate(ptr, l);
index c11b5a851048f631c03532712c5a753dff1ac0a1..24cabb395649c21766fd4234f7a89826ff9a846e 100644 (file)
@@ -8,7 +8,7 @@ LL |     unsafe { __rust_realloc(ptr, layout.size(), layout.align(), new_size) }
    = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
    = note: BACKTRACE:
    = note: inside `std::alloc::realloc` at RUSTLIB/alloc/src/alloc.rs:LL:CC
-note: inside `main` at $DIR/reallocate-bad-size.rs:LL:CC
+note: inside `main`
   --> $DIR/reallocate-bad-size.rs:LL:CC
    |
 LL |         let _y = realloc(x, Layout::from_size_align_unchecked(2, 1), 1);
index c7db5a729048c234e899a153ef03dfc2d74d6fc8..b1460bfb763eed3d219accd982bdfbef528c11b8 100644 (file)
@@ -8,7 +8,7 @@ LL |     unsafe { __rust_realloc(ptr, layout.size(), layout.align(), new_size) }
    = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
    = note: BACKTRACE:
    = note: inside `std::alloc::realloc` at RUSTLIB/alloc/src/alloc.rs:LL:CC
-note: inside `main` at $DIR/reallocate-dangling.rs:LL:CC
+note: inside `main`
   --> $DIR/reallocate-dangling.rs:LL:CC
    |
 LL |         let _z = realloc(x, Layout::from_size_align_unchecked(1, 1), 1);
index 44991542b135074d8fc1087f290fe7e74da10b6a..b1636050a78ca70972762891a49342f57d66049c 100644 (file)
@@ -12,7 +12,7 @@ LL |     unsafe { __rust_dealloc(ptr, layout.size(), layout.align()) }
    = note: inside `alloc::alloc::box_free::<i32, std::alloc::Global>` at RUSTLIB/alloc/src/alloc.rs:LL:CC
    = note: inside `std::ptr::drop_in_place::<std::boxed::Box<i32>> - shim(Some(std::boxed::Box<i32>))` at RUSTLIB/core/src/ptr/mod.rs:LL:CC
    = note: inside `std::mem::drop::<std::boxed::Box<i32>>` at RUSTLIB/core/src/mem/mod.rs:LL:CC
-note: inside `main` at $DIR/stack_free.rs:LL:CC
+note: inside `main`
   --> $DIR/stack_free.rs:LL:CC
    |
 LL |     drop(bad_box);
index 83701639976877fae534904ea29c8d878643d99f..f57b52c4bda7a14943ba15cc87f305851f85c4d6 100644 (file)
@@ -21,7 +21,7 @@ LL |     let res = helper(val, ptr);
    |                      ^^^
    = note: BACKTRACE:
    = note: inside `helper` at $DIR/box-cell-alias.rs:LL:CC
-note: inside `main` at $DIR/box-cell-alias.rs:LL:CC
+note: inside `main`
   --> $DIR/box-cell-alias.rs:LL:CC
    |
 LL |     let res = helper(val, ptr);
index 20f34cf104d63f1b6f1f83c641ce34cf79b82600..7b297b260d87ab2ce141265147188e8a195132ce 100644 (file)
@@ -10,7 +10,7 @@ LL |         let rc = unsafe { c::WaitForSingleObject(self.handle.as_raw_handle(
    = note: inside `std::sys::PLATFORM::thread::Thread::join` at RUSTLIB/std/src/sys/PLATFORM/thread.rs:LL:CC
    = note: inside `std::thread::JoinInner::<'_, ()>::join` at RUSTLIB/std/src/thread/mod.rs:LL:CC
    = note: inside `std::thread::JoinHandle::<()>::join` at RUSTLIB/std/src/thread/mod.rs:LL:CC
-note: inside `main` at $DIR/windows_join_detached.rs:LL:CC
+note: inside `main`
   --> $DIR/windows_join_detached.rs:LL:CC
    |
 LL |     thread.join().unwrap();
index 5a80d1ac5a9b1a11245cd946448be605d02b9cc4..1e7dfaa7499041851561a4da9b354f1b33b6dd95 100644 (file)
@@ -6,7 +6,7 @@ LL |         let res = syscall!(epoll_create1(libc::EPOLL_CLOEXEC));
    |
    = help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support
    = note: BACKTRACE:
-note: inside `main` at $DIR/tokio_mvp.rs:LL:CC
+note: inside `main`
   --> $DIR/tokio_mvp.rs:LL:CC
    |
 LL | #[tokio::main]
index 72e5f20f924a42bfef5a3c184bff4590b6af6c2d..2ba8116cadc247ca710e303e2a2b2fd529c2cfd7 100644 (file)
@@ -8,7 +8,7 @@ LL |     unsafe { &mut *(LEAK as *mut i32) };
    = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
    = note: BACKTRACE:
    = note: inside `evil` at $DIR/storage_dead_dangling.rs:LL:CC
-note: inside `main` at $DIR/storage_dead_dangling.rs:LL:CC
+note: inside `main`
   --> $DIR/storage_dead_dangling.rs:LL:CC
    |
 LL |     evil();
index 5de27108ab633bcfa3e4e90a873bc1f4114e4a8a..0075f877b29dc9b12fb6afceaaaaad85a6e91938 100644 (file)
@@ -8,7 +8,7 @@ LL | }
    = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
    = note: BACKTRACE:
    = note: inside `race` at $DIR/stack_pop_race.rs:LL:CC
-note: inside `main` at $DIR/stack_pop_race.rs:LL:CC
+note: inside `main`
   --> $DIR/stack_pop_race.rs:LL:CC
    |
 LL |     race(0);
index dbf72b5b61ad932b7bd5792cf1b5623f9ea4f9ae..50a0e8e6edef8e551c36a89056c9d52212501c55 100644 (file)
@@ -12,7 +12,7 @@ fn main() {
     #[cfg(fn_ptr)]
     unsafe {
         std::mem::transmute::<unsafe fn(), unsafe extern "C" fn()>(foo)();
-        //[fn_ptr]~^ ERROR: calling a function with calling convention Rust using calling convention C
+        //~[fn_ptr]^ ERROR: calling a function with calling convention Rust using calling convention C
     }
 
     // `Instance` caching should not suppress ABI check.
@@ -28,8 +28,8 @@ fn main() {
         }
         unsafe {
             foo();
-            //[no_cache]~^ ERROR: calling a function with calling convention Rust using calling convention C
-            //[cache]~| ERROR: calling a function with calling convention Rust using calling convention C
+            //~[no_cache]^ ERROR: calling a function with calling convention Rust using calling convention C
+            //~[cache]| ERROR: calling a function with calling convention Rust using calling convention C
         }
     }
 }
index 7d9302e3e3adc27c171cfb5d09c24800ea7f2fb5..484f703f9c1b52dba2f20f664a4a73eb45174e99 100644 (file)
@@ -11,7 +11,7 @@ LL | | }
    | |_^ the program aborted execution
    |
    = note: inside `nounwind` at $DIR/exported_symbol_bad_unwind2.rs:LL:CC
-note: inside `main` at $DIR/exported_symbol_bad_unwind2.rs:LL:CC
+note: inside `main`
   --> $DIR/exported_symbol_bad_unwind2.rs:LL:CC
    |
 LL |     unsafe { nounwind() }
index 7d9302e3e3adc27c171cfb5d09c24800ea7f2fb5..484f703f9c1b52dba2f20f664a4a73eb45174e99 100644 (file)
@@ -11,7 +11,7 @@ LL | | }
    | |_^ the program aborted execution
    |
    = note: inside `nounwind` at $DIR/exported_symbol_bad_unwind2.rs:LL:CC
-note: inside `main` at $DIR/exported_symbol_bad_unwind2.rs:LL:CC
+note: inside `main`
   --> $DIR/exported_symbol_bad_unwind2.rs:LL:CC
    |
 LL |     unsafe { nounwind() }
index f85ad5ae5072fb3619b9668739bc3d7313489124..554cbe09cf03d18d4c29b47b3b1779e600246166 100644 (file)
@@ -4,8 +4,8 @@
 #[cfg_attr(any(definition, both), rustc_nounwind)]
 #[no_mangle]
 extern "C-unwind" fn nounwind() {
-    //[definition]~^ ERROR: abnormal termination: the program aborted execution
-    //[both]~^^ ERROR: abnormal termination: the program aborted execution
+    //~[definition]^ ERROR: abnormal termination: the program aborted execution
+    //~[both]^^ ERROR: abnormal termination: the program aborted execution
     panic!();
 }
 
@@ -15,5 +15,5 @@ fn main() {
         fn nounwind();
     }
     unsafe { nounwind() }
-    //[extern_block]~^ ERROR: unwinding past a stack frame that does not allow unwinding
+    //~[extern_block]^ ERROR: unwinding past a stack frame that does not allow unwinding
 }
index 4f73671a7894796a7fc577e0f6171cf0f21173bb..80c5794736a9f9b1bcc309e3262cd4482bf8902d 100644 (file)
@@ -8,13 +8,13 @@ LL |         *num += 1;
    = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
    = note: BACKTRACE:
    = note: inside closure at $DIR/generator-pinned-moved.rs:LL:CC
-note: inside `<GeneratorIteratorAdapter<[static generator@$DIR/generator-pinned-moved.rs:LL:CC]> as std::iter::Iterator>::next` at $DIR/generator-pinned-moved.rs:LL:CC
+note: inside `<GeneratorIteratorAdapter<[static generator@$DIR/generator-pinned-moved.rs:LL:CC]> as std::iter::Iterator>::next`
   --> $DIR/generator-pinned-moved.rs:LL:CC
    |
 LL |         match me.resume(()) {
    |               ^^^^^^^^^^^^^
    = note: inside `<std::boxed::Box<GeneratorIteratorAdapter<[static generator@$DIR/generator-pinned-moved.rs:LL:CC]>> as std::iter::Iterator>::next` at RUSTLIB/alloc/src/boxed.rs:LL:CC
-note: inside `main` at $DIR/generator-pinned-moved.rs:LL:CC
+note: inside `main`
   --> $DIR/generator-pinned-moved.rs:LL:CC
    |
 LL |     generator_iterator_2.next(); // and use moved value
index 36bb9643b48d4aa8517f24f56894b77b8e2cfe8b..5c73c76a1613d3119ca8eae60cf92dcc880d6d1b 100644 (file)
@@ -8,7 +8,7 @@ LL |         unsafe { intrinsics::simd_cast(self) }
    = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
    = note: BACKTRACE:
    = note: inside `std::simd::Simd::<f32, 2>::to_int_unchecked::<i32>` at RUSTLIB/core/src/../../portable-simd/crates/core_simd/src/vector.rs:LL:CC
-note: inside `main` at $DIR/simd-float-to-int.rs:LL:CC
+note: inside `main`
   --> $DIR/simd-float-to-int.rs:LL:CC
    |
 LL |         let _x: i32x2 = f32x2::from_array([f32::MAX, f32::MIN]).to_int_unchecked();
index 29a4ef65705ab13d58d5a44b67ea3df531b6c165..7512d57f6720e3836a21d8044882923fe665169f 100644 (file)
@@ -8,7 +8,7 @@ LL |         unsafe { intrinsics::simd_gather(or, ptrs, enable.to_int()) }
    = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
    = note: BACKTRACE:
    = note: inside `std::simd::Simd::<i8, 4>::gather_select_unchecked` at RUSTLIB/core/src/../../portable-simd/crates/core_simd/src/vector.rs:LL:CC
-note: inside `main` at $DIR/simd-gather.rs:LL:CC
+note: inside `main`
   --> $DIR/simd-gather.rs:LL:CC
    |
 LL |         let _result = Simd::gather_select_unchecked(&vec, Mask::splat(true), idxs, Simd::splat(0));
index fde85a63503b6bf085915d5b8f46eb55b711740b..a9ad60a0e5be2218a57b1a29b5b5cf5afbfccd1f 100644 (file)
@@ -8,7 +8,7 @@ LL |             intrinsics::simd_scatter(self, ptrs, enable.to_int())
    = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
    = note: BACKTRACE:
    = note: inside `std::simd::Simd::<i8, 4>::scatter_select_unchecked` at RUSTLIB/core/src/../../portable-simd/crates/core_simd/src/vector.rs:LL:CC
-note: inside `main` at $DIR/simd-scatter.rs:LL:CC
+note: inside `main`
   --> $DIR/simd-scatter.rs:LL:CC
    |
 LL | /         Simd::from_array([-27, 82, -41, 124]).scatter_select_unchecked(
index e6644a72849ff6c63172be08e03102e8bd2861da..f1cb50ab9be788b384ed98693b0812f7baa2142c 100644 (file)
@@ -8,7 +8,7 @@ LL |         let obj = std::mem::transmute::<FatPointer, *mut FunnyPointer>(obj)
    = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
    = note: BACKTRACE:
    = note: inside `FunnyPointer::from_data_ptr` at $DIR/issue-miri-1112.rs:LL:CC
-note: inside `main` at $DIR/issue-miri-1112.rs:LL:CC
+note: inside `main`
   --> $DIR/issue-miri-1112.rs:LL:CC
    |
 LL |         let _raw: &FunnyPointer = FunnyPointer::from_data_ptr(&hello, &meta as *const _);
index 4c3a3d075f02843f802af644759acde725e624ab..413172b25464a683451b6652cced69565b029d4c 100644 (file)
@@ -8,7 +8,7 @@ LL |         match v.0 {}
    = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
    = note: BACKTRACE:
    = note: inside `m::f` at $DIR/never_transmute_void.rs:LL:CC
-note: inside `main` at $DIR/never_transmute_void.rs:LL:CC
+note: inside `main`
   --> $DIR/never_transmute_void.rs:LL:CC
    |
 LL |     m::f(v);
index 23c33f5e7f3ff0409dd91ed84f820ff7446161be..5d7f01f4786561ffe5700a2927c47672d56f867a 100644 (file)
@@ -13,7 +13,7 @@ LL |     std::panic::catch_unwind(|| unwind()).unwrap_err();
    = note: inside `std::panicking::r#try::do_call::<[closure@$DIR/bad_unwind.rs:LL:CC], ()>` at RUSTLIB/std/src/panicking.rs:LL:CC
    = note: inside `std::panicking::r#try::<(), [closure@$DIR/bad_unwind.rs:LL:CC]>` at RUSTLIB/std/src/panicking.rs:LL:CC
    = note: inside `std::panic::catch_unwind::<[closure@$DIR/bad_unwind.rs:LL:CC], ()>` at RUSTLIB/std/src/panic.rs:LL:CC
-note: inside `main` at $DIR/bad_unwind.rs:LL:CC
+note: inside `main`
   --> $DIR/bad_unwind.rs:LL:CC
    |
 LL |     std::panic::catch_unwind(|| unwind()).unwrap_err();
index f1d2b4de97cc2f0847f702146fbf5c89dfc118e9..6bf13f21601503766daadfb984df0585078d9511 100644 (file)
@@ -75,13 +75,13 @@ LL |     ABORT();
    = note: inside `std::panicking::rust_panic_with_hook` at RUSTLIB/std/src/panicking.rs:LL:CC
    = note: inside closure at RUSTLIB/std/src/panicking.rs:LL:CC
    = note: inside `std::sys_common::backtrace::__rust_end_short_backtrace::<[closure@std::rt::begin_panic<&str>::{closure#0}], !>` at RUSTLIB/std/src/sys_common/backtrace.rs:LL:CC
-note: inside `<Foo as std::ops::Drop>::drop` at RUSTLIB/std/src/panic.rs:LL:CC
+note: inside `<Foo as std::ops::Drop>::drop`
   --> $DIR/double_panic.rs:LL:CC
    |
 LL |         panic!("second");
    | ^
    = note: inside `std::ptr::drop_in_place::<Foo> - shim(Some(Foo))` at RUSTLIB/core/src/ptr/mod.rs:LL:CC
-note: inside `main` at $DIR/double_panic.rs:LL:CC
+note: inside `main`
   --> $DIR/double_panic.rs:LL:CC
    |
 LL | }
index 568b286e1d3bf5733984e3273f00801d74b8282a..39ad0d268b94ea9b9e58f515a1b3e467abf32efe 100644 (file)
@@ -6,7 +6,7 @@ LL |     core::intrinsics::abort();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^ the program aborted execution
    |
    = note: inside `panic_handler` at $DIR/no_std.rs:LL:CC
-note: inside `start` at RUSTLIB/core/src/panic.rs:LL:CC
+note: inside `start`
   --> $DIR/no_std.rs:LL:CC
    |
 LL |     panic!("blarg I am dead")
index 75471994546431d4c01d837c3b544838d79aa0d4..d25dd7be63596e3761edc033cef1df496d65cfac 100644 (file)
@@ -12,7 +12,7 @@ LL |                 ABORT();
    = note: inside `std::panicking::rust_panic_with_hook` at RUSTLIB/std/src/panicking.rs:LL:CC
    = note: inside closure at RUSTLIB/std/src/panicking.rs:LL:CC
    = note: inside `std::sys_common::backtrace::__rust_end_short_backtrace::<[closure@std::rt::begin_panic<&str>::{closure#0}], !>` at RUSTLIB/std/src/sys_common/backtrace.rs:LL:CC
-note: inside `main` at RUSTLIB/std/src/panic.rs:LL:CC
+note: inside `main`
   --> $DIR/panic_abort1.rs:LL:CC
    |
 LL |     std::panic!("panicking from libstd");
index 2fdf889d798a2b3d668ccb8596621565f84b2202..f56d509a697b4661f22c9e9bf092adf87a05bdcc 100644 (file)
@@ -13,7 +13,7 @@ LL |                 ABORT();
    = note: inside closure at RUSTLIB/std/src/panicking.rs:LL:CC
    = note: inside `std::sys_common::backtrace::__rust_end_short_backtrace::<[closure@std::panicking::begin_panic_handler::{closure#0}], !>` at RUSTLIB/std/src/sys_common/backtrace.rs:LL:CC
    = note: inside `std::panicking::begin_panic_handler` at RUSTLIB/std/src/panicking.rs:LL:CC
-note: inside `main` at RUSTLIB/std/src/panic.rs:LL:CC
+note: inside `main`
   --> $DIR/panic_abort2.rs:LL:CC
    |
 LL |     std::panic!("{}-panicking from libstd", 42);
index 8704b0d940b7a5ce7eb12039e36992b96f2bd32d..43792f769930b6a7964dce2220018619d03cfccc 100644 (file)
@@ -13,7 +13,7 @@ LL |                 ABORT();
    = note: inside closure at RUSTLIB/std/src/panicking.rs:LL:CC
    = note: inside `std::sys_common::backtrace::__rust_end_short_backtrace::<[closure@std::panicking::begin_panic_handler::{closure#0}], !>` at RUSTLIB/std/src/sys_common/backtrace.rs:LL:CC
    = note: inside `std::panicking::begin_panic_handler` at RUSTLIB/std/src/panicking.rs:LL:CC
-note: inside `main` at RUSTLIB/core/src/panic.rs:LL:CC
+note: inside `main`
   --> $DIR/panic_abort3.rs:LL:CC
    |
 LL |     core::panic!("panicking from libcore");
index 1d75d72c0317cf777ecd2e44ca9d39acf179737e..89e181bfb276c984a5deb2bb9eee286fbe09d8d5 100644 (file)
@@ -13,7 +13,7 @@ LL |                 ABORT();
    = note: inside closure at RUSTLIB/std/src/panicking.rs:LL:CC
    = note: inside `std::sys_common::backtrace::__rust_end_short_backtrace::<[closure@std::panicking::begin_panic_handler::{closure#0}], !>` at RUSTLIB/std/src/sys_common/backtrace.rs:LL:CC
    = note: inside `std::panicking::begin_panic_handler` at RUSTLIB/std/src/panicking.rs:LL:CC
-note: inside `main` at RUSTLIB/core/src/panic.rs:LL:CC
+note: inside `main`
   --> $DIR/panic_abort4.rs:LL:CC
    |
 LL |     core::panic!("{}-panicking from libcore", 42);
index f7c5f6046e198f14b733c5b1883a7209a73b78ad..042d8cd4afe79a99d13573491d3925a3b85c5f46 100644 (file)
@@ -8,7 +8,7 @@ LL |         let _val = *left_ptr;
    = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
    = note: BACKTRACE:
    = note: inside `deref` at $DIR/provenance_transmute.rs:LL:CC
-note: inside `main` at $DIR/provenance_transmute.rs:LL:CC
+note: inside `main`
   --> $DIR/provenance_transmute.rs:LL:CC
    |
 LL |         deref(ptr1, ptr2.with_addr(ptr1.addr()));
index 269b1383aad68312bd2848831ce7cc25fd2bfb5b..2385439c8a5f7f85ae007287cfeb6e08313cf33b 100644 (file)
@@ -17,7 +17,7 @@ LL |         let fd = cvt_r(|| unsafe { open64(path.as_ptr(), flags, opts.mode a
    = note: inside `std::fs::OpenOptions::_open` at RUSTLIB/std/src/fs.rs:LL:CC
    = note: inside `std::fs::OpenOptions::open::<&std::path::Path>` at RUSTLIB/std/src/fs.rs:LL:CC
    = note: inside `std::fs::File::open::<&str>` at RUSTLIB/std/src/fs.rs:LL:CC
-note: inside `main` at $DIR/isolated_file.rs:LL:CC
+note: inside `main`
   --> $DIR/isolated_file.rs:LL:CC
    |
 LL |     let _file = std::fs::File::open("file.txt").unwrap();
index 414ac1cb1b70260184db2afb46636b990bc40e2c..35ff1926b065740d35e30966228e67c0af9d4e78 100644 (file)
@@ -8,7 +8,7 @@ LL |     let _fd = unsafe { libc::mkstemp(s) };
    = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
    = note: BACKTRACE:
    = note: inside `test_mkstemp_immutable_arg` at $DIR/mkstemp_immutable_arg.rs:LL:CC
-note: inside `main` at $DIR/mkstemp_immutable_arg.rs:LL:CC
+note: inside `main`
   --> $DIR/mkstemp_immutable_arg.rs:LL:CC
    |
 LL |     test_mkstemp_immutable_arg();
index 38d033b494554e243201f06d8c8956e8f566bad0..5a8e7352c768618f53b3cc47ef3b9b95481fc494 100644 (file)
@@ -8,7 +8,7 @@ LL | ...safe { libc::open(name_ptr, libc::O_CREAT) };
    = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
    = note: BACKTRACE:
    = note: inside `test_file_open_missing_needed_mode` at $DIR/unix_open_missing_required_mode.rs:LL:CC
-note: inside `main` at $DIR/unix_open_missing_required_mode.rs:LL:CC
+note: inside `main`
   --> $DIR/unix_open_missing_required_mode.rs:LL:CC
    |
 LL |     test_file_open_missing_needed_mode();
index 8a24b085a99f6f56e3f3280918db0b8295ec40d2..325565fa1e786aa327cd337838c91979fa9aa080 100644 (file)
@@ -8,7 +8,7 @@ LL |             std::hint::unreachable_unchecked();
    = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
    = note: BACKTRACE:
    = note: inside `test_cpp20_rwc_syncs` at $DIR/cpp20_rwc_syncs.rs:LL:CC
-note: inside `main` at $DIR/cpp20_rwc_syncs.rs:LL:CC
+note: inside `main`
   --> $DIR/cpp20_rwc_syncs.rs:LL:CC
    |
 LL |         test_cpp20_rwc_syncs();
index 268d253ad5b06c65b49b5d9ac60914c231ff0608..4514abb4ab2e47900200bc4dde0ababfa159fe4a 100644 (file)
@@ -18,7 +18,7 @@ LL | pub fn safe(_x: &mut i32, _y: &mut i32) {}
    |             ^^
    = note: BACKTRACE:
    = note: inside `safe` at $DIR/aliasing_mut1.rs:LL:CC
-note: inside `main` at $DIR/aliasing_mut1.rs:LL:CC
+note: inside `main`
   --> $DIR/aliasing_mut1.rs:LL:CC
    |
 LL |     safe_raw(xraw, xraw);
index 77a542f45a2566a5f61af86f328921e92d07c668..9ca9743cbd929be46fb3418a504316321bb3cc9c 100644 (file)
@@ -18,7 +18,7 @@ LL | pub fn safe(_x: &i32, _y: &mut i32) {}
    |             ^^
    = note: BACKTRACE:
    = note: inside `safe` at $DIR/aliasing_mut2.rs:LL:CC
-note: inside `main` at $DIR/aliasing_mut2.rs:LL:CC
+note: inside `main`
   --> $DIR/aliasing_mut2.rs:LL:CC
    |
 LL |     safe_raw(xshr, xraw);
index eb6b01fc6b12bfa02690ee435ce24717923aecd6..b504097a3c91f2541339f527e04e3edf93c545af 100644 (file)
@@ -21,7 +21,7 @@ LL |     safe_raw(xraw, xshr);
    |     ^^^^^^^^^^^^^^^^^^^^
    = note: BACKTRACE:
    = note: inside `safe` at $DIR/aliasing_mut3.rs:LL:CC
-note: inside `main` at $DIR/aliasing_mut3.rs:LL:CC
+note: inside `main`
   --> $DIR/aliasing_mut3.rs:LL:CC
    |
 LL |     safe_raw(xraw, xshr);
index e592b154a7326326da9226cf42c2876ba35f4699..6fe0d70902930fe864390ec1e7c0f9914d77dc21 100644 (file)
@@ -18,7 +18,7 @@ LL | pub fn safe(_x: &i32, _y: &mut Cell<i32>) {}
    |             ^^
    = note: BACKTRACE:
    = note: inside `safe` at $DIR/aliasing_mut4.rs:LL:CC
-note: inside `main` at $DIR/aliasing_mut4.rs:LL:CC
+note: inside `main`
   --> $DIR/aliasing_mut4.rs:LL:CC
    |
 LL |     safe_raw(xshr, xraw as *mut _);
index d82b8342f1231e9828a31bf1cd757859a1c3b04c..f114130f6fafdabece908fc8999b7a357ffc0d0e 100644 (file)
@@ -21,12 +21,12 @@ LL |     *our = 5;
    |     ^^^^^^^^
    = note: BACKTRACE:
    = note: inside `unknown_code_2` at $DIR/box_exclusive_violation1.rs:LL:CC
-note: inside `demo_box_advanced_unique` at $DIR/box_exclusive_violation1.rs:LL:CC
+note: inside `demo_box_advanced_unique`
   --> $DIR/box_exclusive_violation1.rs:LL:CC
    |
 LL |     unknown_code_2();
    |     ^^^^^^^^^^^^^^^^
-note: inside `main` at $DIR/box_exclusive_violation1.rs:LL:CC
+note: inside `main`
   --> $DIR/box_exclusive_violation1.rs:LL:CC
    |
 LL |     demo_box_advanced_unique(Box::new(0));
index 3c84cbcfd5182a0b543111003d38052a8e498bb4..139fcd0ca4583d67502bb5e41081831f0b902093 100644 (file)
@@ -18,7 +18,7 @@ LL | unsafe fn test(mut x: Box<i32>, y: *const i32) -> i32 {
    |                ^^^^^
    = note: BACKTRACE:
    = note: inside `test` at $DIR/box_noalias_violation.rs:LL:CC
-note: inside `main` at $DIR/box_noalias_violation.rs:LL:CC
+note: inside `main`
   --> $DIR/box_noalias_violation.rs:LL:CC
    |
 LL |         test(Box::from_raw(ptr), ptr);
index bb3eaec1e85c0da033b0f68073849a304ae21b71..516964b9a4e6f11a95cc3195d2af7da83ab5ef86 100644 (file)
@@ -12,18 +12,18 @@ LL |     unsafe { __rust_dealloc(ptr, layout.size(), layout.align()) }
    = note: inside `alloc::alloc::box_free::<i32, std::alloc::Global>` at RUSTLIB/alloc/src/alloc.rs:LL:CC
    = note: inside `std::ptr::drop_in_place::<std::boxed::Box<i32>> - shim(Some(std::boxed::Box<i32>))` at RUSTLIB/core/src/ptr/mod.rs:LL:CC
    = note: inside `std::mem::drop::<std::boxed::Box<i32>>` at RUSTLIB/core/src/mem/mod.rs:LL:CC
-note: inside closure at $DIR/deallocate_against_protector1.rs:LL:CC
+note: inside closure
   --> $DIR/deallocate_against_protector1.rs:LL:CC
    |
 LL |         drop(unsafe { Box::from_raw(raw) });
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    = note: inside `<[closure@$DIR/deallocate_against_protector1.rs:LL:CC] as std::ops::FnOnce<(&mut i32,)>>::call_once - shim` at RUSTLIB/core/src/ops/function.rs:LL:CC
-note: inside `inner` at $DIR/deallocate_against_protector1.rs:LL:CC
+note: inside `inner`
   --> $DIR/deallocate_against_protector1.rs:LL:CC
    |
 LL |     f(x)
    |     ^^^^
-note: inside `main` at $DIR/deallocate_against_protector1.rs:LL:CC
+note: inside `main`
   --> $DIR/deallocate_against_protector1.rs:LL:CC
    |
 LL | /     inner(Box::leak(Box::new(0)), |x| {
index 25bab1aa564a65a0145bb1506cda9ded5c95e453..47cfa0de7258c1fe0263442c8387a6d7b3d7a7d9 100644 (file)
@@ -12,18 +12,18 @@ LL |     unsafe { __rust_dealloc(ptr, layout.size(), layout.align()) }
    = note: inside `alloc::alloc::box_free::<NotUnpin, std::alloc::Global>` at RUSTLIB/alloc/src/alloc.rs:LL:CC
    = note: inside `std::ptr::drop_in_place::<std::boxed::Box<NotUnpin>> - shim(Some(std::boxed::Box<NotUnpin>))` at RUSTLIB/core/src/ptr/mod.rs:LL:CC
    = note: inside `std::mem::drop::<std::boxed::Box<NotUnpin>>` at RUSTLIB/core/src/mem/mod.rs:LL:CC
-note: inside closure at $DIR/deallocate_against_protector2.rs:LL:CC
+note: inside closure
   --> $DIR/deallocate_against_protector2.rs:LL:CC
    |
 LL |         drop(unsafe { Box::from_raw(raw) });
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    = note: inside `<[closure@$DIR/deallocate_against_protector2.rs:LL:CC] as std::ops::FnOnce<(&mut NotUnpin,)>>::call_once - shim` at RUSTLIB/core/src/ops/function.rs:LL:CC
-note: inside `inner` at $DIR/deallocate_against_protector2.rs:LL:CC
+note: inside `inner`
   --> $DIR/deallocate_against_protector2.rs:LL:CC
    |
 LL |     f(x)
    |     ^^^^
-note: inside `main` at $DIR/deallocate_against_protector2.rs:LL:CC
+note: inside `main`
   --> $DIR/deallocate_against_protector2.rs:LL:CC
    |
 LL | /     inner(Box::leak(Box::new(NotUnpin(0, PhantomPinned))), |x| {
index 3b7802901a54eb723ddf23ae38b9b557d1772a2c..f2f13d0d5594ea1215bf7f43a95560e05325a390 100644 (file)
@@ -18,7 +18,7 @@ LL |         ptr1.write(0);
    |         ^^^^^^^^^^^^^
    = note: BACKTRACE:
    = note: inside `std::alloc::dealloc` at RUSTLIB/alloc/src/alloc.rs:LL:CC
-note: inside `main` at $DIR/illegal_deALLOC.rs:LL:CC
+note: inside `main`
   --> $DIR/illegal_deALLOC.rs:LL:CC
    |
 LL |         dealloc(ptr2, Layout::from_size_align_unchecked(1, 1));
index 1a627b8a883009f07818308cbe6f48f916bb21ac..49d9050f3094771d1f44672fec01770dc6b0c89c 100644 (file)
@@ -18,7 +18,7 @@ LL | fn foo(a: &mut u32, y: *mut u32) -> u32 {
    |        ^
    = note: BACKTRACE:
    = note: inside `foo` at $DIR/illegal_write6.rs:LL:CC
-note: inside `main` at $DIR/illegal_write6.rs:LL:CC
+note: inside `main`
   --> $DIR/illegal_write6.rs:LL:CC
    |
 LL |     foo(x, p);
index 1ef36b7ac10fc4c5005ded98d127b7968315d580..a53c633c3813076df0bc1a336970017d5430fc5a 100644 (file)
@@ -18,7 +18,7 @@ LL | fn inner(x: *mut i32, _y: &mut i32) {
    |                       ^^
    = note: BACKTRACE:
    = note: inside `inner` at $DIR/invalidate_against_protector1.rs:LL:CC
-note: inside `main` at $DIR/invalidate_against_protector1.rs:LL:CC
+note: inside `main`
   --> $DIR/invalidate_against_protector1.rs:LL:CC
    |
 LL |     inner(xraw, xref);
index 941b936e5d7249443852d9692444911c5cd8c898..6ee78d1aac682fd9c79e4286525f627dcf37e269 100644 (file)
@@ -18,7 +18,7 @@ LL | fn inner(x: *mut i32, _y: &i32) {
    |                       ^^
    = note: BACKTRACE:
    = note: inside `inner` at $DIR/invalidate_against_protector2.rs:LL:CC
-note: inside `main` at $DIR/invalidate_against_protector2.rs:LL:CC
+note: inside `main`
   --> $DIR/invalidate_against_protector2.rs:LL:CC
    |
 LL |     inner(xraw, xref);
index 176a859ee8af7692d4b1673d1ce96b03eff79019..2b38dea9dbb719221b89285fd97ba785fd53fa6a 100644 (file)
@@ -18,7 +18,7 @@ LL | fn inner(x: *mut i32, _y: &i32) {
    |                       ^^
    = note: BACKTRACE:
    = note: inside `inner` at $DIR/invalidate_against_protector3.rs:LL:CC
-note: inside `main` at $DIR/invalidate_against_protector3.rs:LL:CC
+note: inside `main`
   --> $DIR/invalidate_against_protector3.rs:LL:CC
    |
 LL |         inner(ptr, &*ptr);
index 16c8810a8e6d90f80cc4ba1361c6eaf3c385890c..c69a3af293c13b1e6b59556a00cf6b64088cb780 100644 (file)
@@ -9,7 +9,7 @@ LL |         Box(unsafe { Unique::new_unchecked(raw) }, alloc)
    = note: BACKTRACE:
    = note: inside `std::boxed::Box::<u32>::from_raw_in` at RUSTLIB/alloc/src/boxed.rs:LL:CC
    = note: inside `std::boxed::Box::<u32>::from_raw` at RUSTLIB/alloc/src/boxed.rs:LL:CC
-note: inside `main` at $DIR/issue-miri-1050-1.rs:LL:CC
+note: inside `main`
   --> $DIR/issue-miri-1050-1.rs:LL:CC
    |
 LL |         drop(Box::from_raw(ptr as *mut u32));
index d57e7662e504aea7fd7959077d72b17e6353f991..23d7fdcd03bc5a3333d409cf0242696b66557ae5 100644 (file)
@@ -9,7 +9,7 @@ LL |         Box(unsafe { Unique::new_unchecked(raw) }, alloc)
    = note: BACKTRACE:
    = note: inside `std::boxed::Box::<i32>::from_raw_in` at RUSTLIB/alloc/src/boxed.rs:LL:CC
    = note: inside `std::boxed::Box::<i32>::from_raw` at RUSTLIB/alloc/src/boxed.rs:LL:CC
-note: inside `main` at $DIR/issue-miri-1050-2.rs:LL:CC
+note: inside `main`
   --> $DIR/issue-miri-1050-2.rs:LL:CC
    |
 LL |         drop(Box::from_raw(ptr.as_ptr()));
index 1c7f8e12d3d78977b4e6c751f7ee822a7137908f..2f3900c40d7261fd8f342e6ecc94d2eacc6e3f07 100644 (file)
@@ -21,12 +21,12 @@ LL |     *our = 5;
    |     ^^^^^^^^
    = note: BACKTRACE:
    = note: inside `unknown_code_2` at $DIR/mut_exclusive_violation1.rs:LL:CC
-note: inside `demo_mut_advanced_unique` at $DIR/mut_exclusive_violation1.rs:LL:CC
+note: inside `demo_mut_advanced_unique`
   --> $DIR/mut_exclusive_violation1.rs:LL:CC
    |
 LL |     unknown_code_2();
    |     ^^^^^^^^^^^^^^^^
-note: inside `main` at $DIR/mut_exclusive_violation1.rs:LL:CC
+note: inside `main`
   --> $DIR/mut_exclusive_violation1.rs:LL:CC
    |
 LL |     demo_mut_advanced_unique(&mut 0);
index 70186dd3a53f3305d9b8622fadf83448f1aae9ad..90677dfaf555e4c8226919cb89f3d08cca536384 100644 (file)
@@ -19,17 +19,17 @@ LL | fn dealloc_while_running(_n: Newtype<'_>, dealloc: impl FnOnce()) {
    = note: BACKTRACE:
    = note: inside `std::boxed::Box::<i32>::from_raw_in` at RUSTLIB/alloc/src/boxed.rs:LL:CC
    = note: inside `std::boxed::Box::<i32>::from_raw` at RUSTLIB/alloc/src/boxed.rs:LL:CC
-note: inside closure at $DIR/newtype_pair_retagging.rs:LL:CC
+note: inside closure
   --> $DIR/newtype_pair_retagging.rs:LL:CC
    |
 LL |             || drop(Box::from_raw(ptr)),
    |                     ^^^^^^^^^^^^^^^^^^
-note: inside `dealloc_while_running::<[closure@$DIR/newtype_pair_retagging.rs:LL:CC]>` at $DIR/newtype_pair_retagging.rs:LL:CC
+note: inside `dealloc_while_running::<[closure@$DIR/newtype_pair_retagging.rs:LL:CC]>`
   --> $DIR/newtype_pair_retagging.rs:LL:CC
    |
 LL |     dealloc();
    |     ^^^^^^^^^
-note: inside `main` at $DIR/newtype_pair_retagging.rs:LL:CC
+note: inside `main`
   --> $DIR/newtype_pair_retagging.rs:LL:CC
    |
 LL | /         dealloc_while_running(
index 69fa27c9c096fef7f6e6c1a3e6a6dfe9287165d5..f189d0483d12d9e459ed3862d1259375ff1cc5f6 100644 (file)
@@ -19,17 +19,17 @@ LL | fn dealloc_while_running(_n: Newtype<'_>, dealloc: impl FnOnce()) {
    = note: BACKTRACE:
    = note: inside `std::boxed::Box::<i32>::from_raw_in` at RUSTLIB/alloc/src/boxed.rs:LL:CC
    = note: inside `std::boxed::Box::<i32>::from_raw` at RUSTLIB/alloc/src/boxed.rs:LL:CC
-note: inside closure at $DIR/newtype_retagging.rs:LL:CC
+note: inside closure
   --> $DIR/newtype_retagging.rs:LL:CC
    |
 LL |             || drop(Box::from_raw(ptr)),
    |                     ^^^^^^^^^^^^^^^^^^
-note: inside `dealloc_while_running::<[closure@$DIR/newtype_retagging.rs:LL:CC]>` at $DIR/newtype_retagging.rs:LL:CC
+note: inside `dealloc_while_running::<[closure@$DIR/newtype_retagging.rs:LL:CC]>`
   --> $DIR/newtype_retagging.rs:LL:CC
    |
 LL |     dealloc();
    |     ^^^^^^^^^
-note: inside `main` at $DIR/newtype_retagging.rs:LL:CC
+note: inside `main`
   --> $DIR/newtype_retagging.rs:LL:CC
    |
 LL | /         dealloc_while_running(
diff --git a/src/tools/miri/tests/fail/stacked_borrows/notunpin_dereferenceable_fakeread.rs b/src/tools/miri/tests/fail/stacked_borrows/notunpin_dereferenceable_fakeread.rs
deleted file mode 100644 (file)
index d660921..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-//! Reborrowing a `&mut !Unpin` must still act like a (fake) read.
-use std::marker::PhantomPinned;
-
-struct NotUnpin(i32, PhantomPinned);
-
-fn main() {
-    unsafe {
-        let mut x = NotUnpin(0, PhantomPinned);
-        // Mutable borrow of `Unpin` field (with lifetime laundering)
-        let fieldref = &mut *(&mut x.0 as *mut i32);
-        // Mutable reborrow of the entire `x`, which is `!Unpin` but should
-        // still count as a read since we would add `dereferenceable`.
-        let _xref = &mut x;
-        // That read should have invalidated `fieldref`.
-        *fieldref = 0; //~ ERROR: /write access .* tag does not exist in the borrow stack/
-    }
-}
diff --git a/src/tools/miri/tests/fail/stacked_borrows/notunpin_dereferenceable_fakeread.stderr b/src/tools/miri/tests/fail/stacked_borrows/notunpin_dereferenceable_fakeread.stderr
deleted file mode 100644 (file)
index 3ef8a8e..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-error: Undefined Behavior: attempting a write access using <TAG> at ALLOC[0x0], but that tag does not exist in the borrow stack for this location
-  --> $DIR/notunpin_dereferenceable_fakeread.rs:LL:CC
-   |
-LL |         *fieldref = 0;
-   |         ^^^^^^^^^^^^^
-   |         |
-   |         attempting a write access using <TAG> at ALLOC[0x0], but that tag does not exist in the borrow stack for this location
-   |         this error occurs as part of an access at ALLOC[0x0..0x4]
-   |
-   = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental
-   = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information
-help: <TAG> was created by a Unique retag at offsets [0x0..0x4]
-  --> $DIR/notunpin_dereferenceable_fakeread.rs:LL:CC
-   |
-LL |         let fieldref = &mut *(&mut x.0 as *mut i32);
-   |                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-help: <TAG> was later invalidated at offsets [0x0..0x4] by a SharedReadWrite retag
-  --> $DIR/notunpin_dereferenceable_fakeread.rs:LL:CC
-   |
-LL |         let _xref = &mut x;
-   |                     ^^^^^^
-   = note: BACKTRACE:
-   = note: inside `main` at $DIR/notunpin_dereferenceable_fakeread.rs:LL:CC
-
-note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
-
-error: aborting due to previous error
-
index 6415af1e18bbff221179930289e7bc9837cb8c49..7d58d1aebbecd6154df1cbb535942b3b4356f735 100644 (file)
@@ -21,7 +21,7 @@ LL |     *val = 2; // this invalidates any raw ptrs `fun1` might have created.
    |     ^^^^^^^^
    = note: BACKTRACE:
    = note: inside `fun2` at $DIR/pointer_smuggling.rs:LL:CC
-note: inside `main` at $DIR/pointer_smuggling.rs:LL:CC
+note: inside `main`
   --> $DIR/pointer_smuggling.rs:LL:CC
    |
 LL |     fun2(); // if they now use a raw ptr they break our reference
index f25d689524d1b3c86a565ea215a7ec5034a5e03a..5dc936f0707443f5805196e164c647ff5c17a238 100644 (file)
@@ -8,7 +8,7 @@ LL |         *p = 5;
    = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
    = note: BACKTRACE:
    = note: inside `thread_2` at $DIR/retag_data_race_read.rs:LL:CC
-note: inside closure at $DIR/retag_data_race_read.rs:LL:CC
+note: inside closure
   --> $DIR/retag_data_race_read.rs:LL:CC
    |
 LL |     let t2 = std::thread::spawn(move || thread_2(p));
index f97e6bb11e9d674a7535cfef0329d4c8397f61aa..03c2450356416586a3d153f6261e01dec8f2c9e2 100644 (file)
@@ -8,7 +8,7 @@ LL |         *p = 5;
    = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
    = note: BACKTRACE:
    = note: inside `thread_2` at $DIR/retag_data_race_write.rs:LL:CC
-note: inside closure at $DIR/retag_data_race_write.rs:LL:CC
+note: inside closure
   --> $DIR/retag_data_race_write.rs:LL:CC
    |
 LL |     let t2 = std::thread::spawn(move || thread_2(p));
index 9deb0c41742f35ea5de0566ecc74e97186e3d58b..1b28f780c1c544a63f0ca9d9850f4539d77f4c09 100644 (file)
@@ -21,7 +21,7 @@ LL |     let _val = unsafe { *xraw }; // invalidate xref
    |                         ^^^^^
    = note: BACKTRACE:
    = note: inside `foo` at $DIR/return_invalid_mut.rs:LL:CC
-note: inside `main` at $DIR/return_invalid_mut.rs:LL:CC
+note: inside `main`
   --> $DIR/return_invalid_mut.rs:LL:CC
    |
 LL |     foo(&mut (1, 2));
index c0ff35ebcde307aa39834ff5a11314ee51345033..db14dcafa008445530d4629312495cc4629ff18d 100644 (file)
@@ -21,7 +21,7 @@ LL |     let _val = unsafe { *xraw }; // invalidate xref
    |                         ^^^^^
    = note: BACKTRACE:
    = note: inside `foo` at $DIR/return_invalid_mut_option.rs:LL:CC
-note: inside `main` at $DIR/return_invalid_mut_option.rs:LL:CC
+note: inside `main`
   --> $DIR/return_invalid_mut_option.rs:LL:CC
    |
 LL |     match foo(&mut (1, 2)) {
index 9abf43c29f08fb3e44601d09e248eeff7288fe9c..81ed4218aade789d54d5ad5598725c862ec98b04 100644 (file)
@@ -21,7 +21,7 @@ LL |     let _val = unsafe { *xraw }; // invalidate xref
    |                         ^^^^^
    = note: BACKTRACE:
    = note: inside `foo` at $DIR/return_invalid_mut_tuple.rs:LL:CC
-note: inside `main` at $DIR/return_invalid_mut_tuple.rs:LL:CC
+note: inside `main`
   --> $DIR/return_invalid_mut_tuple.rs:LL:CC
    |
 LL |     foo(&mut (1, 2)).0;
index dd651517c2fb083b5dae72826dae09955f39ddfc..9c8cc50b2d7ac7b4c87399b9f1ecd4c99a6b34d0 100644 (file)
@@ -21,7 +21,7 @@ LL |     unsafe { *xraw = (42, 23) }; // unfreeze
    |              ^^^^^^^^^^^^^^^^
    = note: BACKTRACE:
    = note: inside `foo` at $DIR/return_invalid_shr.rs:LL:CC
-note: inside `main` at $DIR/return_invalid_shr.rs:LL:CC
+note: inside `main`
   --> $DIR/return_invalid_shr.rs:LL:CC
    |
 LL |     foo(&mut (1, 2));
index 6066bf89f5d095806cab091431260eebca461801..00ce6f6cd5fe129e6f13fe9c26c32b1fcc2440e3 100644 (file)
@@ -21,7 +21,7 @@ LL |     unsafe { *xraw = (42, 23) }; // unfreeze
    |              ^^^^^^^^^^^^^^^^
    = note: BACKTRACE:
    = note: inside `foo` at $DIR/return_invalid_shr_option.rs:LL:CC
-note: inside `main` at $DIR/return_invalid_shr_option.rs:LL:CC
+note: inside `main`
   --> $DIR/return_invalid_shr_option.rs:LL:CC
    |
 LL |     match foo(&mut (1, 2)) {
index 52d365246a74441852bee7c4f2912844c3933159..bbd17b1284c5e6b9508cf5e55de49edd544771a5 100644 (file)
@@ -21,7 +21,7 @@ LL |     unsafe { *xraw = (42, 23) }; // unfreeze
    |              ^^^^^^^^^^^^^^^^
    = note: BACKTRACE:
    = note: inside `foo` at $DIR/return_invalid_shr_tuple.rs:LL:CC
-note: inside `main` at $DIR/return_invalid_shr_tuple.rs:LL:CC
+note: inside `main`
   --> $DIR/return_invalid_shr_tuple.rs:LL:CC
    |
 LL |     foo(&mut (1, 2)).0;
index 0818d07da48e5e776a7f3cae4bd04343a2e6829e..fe0ac211318aac832bd587bf2a4a69fbc3b1fbcf 100644 (file)
@@ -16,12 +16,12 @@ LL |         *(x as *const i32 as *mut i32) = 7;
    |           ^
    = note: BACKTRACE:
    = note: inside `unknown_code` at $DIR/shr_frozen_violation1.rs:LL:CC
-note: inside `foo` at $DIR/shr_frozen_violation1.rs:LL:CC
+note: inside `foo`
   --> $DIR/shr_frozen_violation1.rs:LL:CC
    |
 LL |     unknown_code(&*x);
    |     ^^^^^^^^^^^^^^^^^
-note: inside `main` at $DIR/shr_frozen_violation1.rs:LL:CC
+note: inside `main`
   --> $DIR/shr_frozen_violation1.rs:LL:CC
    |
 LL |     println!("{}", foo(&mut 0));
index 86f1da1f70a33de4b1d549a906bf0051bce68101..e134ee2845d05ea1871bdb3a23b3d1490cd09846 100644 (file)
@@ -16,7 +16,7 @@ LL |         assert_eq!(*s.get_unchecked(1), 2);
    |                     ^^^^^^^^^^^^^^^^^^
    = note: BACKTRACE:
    = note: inside `core::slice::<impl [i32]>::get_unchecked::<usize>` at RUSTLIB/core/src/slice/mod.rs:LL:CC
-note: inside `main` at $DIR/zst_slice.rs:LL:CC
+note: inside `main`
   --> $DIR/zst_slice.rs:LL:CC
    |
 LL |         assert_eq!(*s.get_unchecked(1), 2);
index a543d59addb145d15057a552d18d79bd7829664e..8da532cfff05b38e458ce1052eb8ac2f13380ad1 100644 (file)
@@ -9,7 +9,7 @@ LL |         let mut order = unsafe { memcmp(left.as_ptr(), right.as_ptr(), len)
    = note: BACKTRACE:
    = note: inside `<u8 as core::slice::cmp::SliceOrd>::compare` at RUSTLIB/core/src/slice/cmp.rs:LL:CC
    = note: inside `core::slice::cmp::<impl std::cmp::Ord for [u8]>::cmp` at RUSTLIB/core/src/slice/cmp.rs:LL:CC
-note: inside `main` at $DIR/uninit_buffer.rs:LL:CC
+note: inside `main`
   --> $DIR/uninit_buffer.rs:LL:CC
    |
 LL |         drop(slice1.cmp(slice2));
index 715d76aa1c2e75a6b4f8002cd9bd852c27798c51..210fc8e109aa4843d90de139b0235150c1540685 100644 (file)
@@ -9,7 +9,7 @@ LL |         let mut order = unsafe { memcmp(left.as_ptr(), right.as_ptr(), len)
    = note: BACKTRACE:
    = note: inside `<u8 as core::slice::cmp::SliceOrd>::compare` at RUSTLIB/core/src/slice/cmp.rs:LL:CC
    = note: inside `core::slice::cmp::<impl std::cmp::Ord for [u8]>::cmp` at RUSTLIB/core/src/slice/cmp.rs:LL:CC
-note: inside `main` at $DIR/uninit_buffer_with_provenance.rs:LL:CC
+note: inside `main`
   --> $DIR/uninit_buffer_with_provenance.rs:LL:CC
    |
 LL |         drop(slice1.cmp(slice2));
diff --git a/src/tools/miri/tests/many-seeds/scoped-thread-leak.rs b/src/tools/miri/tests/many-seeds/scoped-thread-leak.rs
new file mode 100644 (file)
index 0000000..f28e436
--- /dev/null
@@ -0,0 +1,8 @@
+//! Regression test for https://github.com/rust-lang/miri/issues/2629
+use std::thread;
+
+fn main() {
+    thread::scope(|s| {
+        s.spawn(|| {});
+    });
+}
index 0001a8dd6eb3376ef463e2777fad597d9dfbe49d..4c2fb40e1102179641d96233433afc38aedb4b8b 100644 (file)
@@ -12,7 +12,7 @@ LL |         let r2 = ((r as usize) + 0) as *mut i32;
    = help: Alternatively, the `-Zmiri-permissive-provenance` flag disables this warning.
    = note: BACKTRACE:
    = note: inside `into_raw` at $DIR/box.rs:LL:CC
-note: inside `main` at $DIR/box.rs:LL:CC
+note: inside `main`
   --> $DIR/box.rs:LL:CC
    |
 LL |     into_raw();
@@ -25,7 +25,7 @@ LL |         let r = ((u.as_ptr() as usize) + 0) as *mut i32;
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ integer-to-pointer cast
    |
    = note: inside `into_unique` at $DIR/box.rs:LL:CC
-note: inside `main` at $DIR/box.rs:LL:CC
+note: inside `main`
   --> $DIR/box.rs:LL:CC
    |
 LL |     into_unique();
diff --git a/src/tools/miri/tests/pass/concurrency/scope.rs b/src/tools/miri/tests/pass/concurrency/scope.rs
new file mode 100644 (file)
index 0000000..ce5d17f
--- /dev/null
@@ -0,0 +1,24 @@
+use std::thread;
+
+fn main() {
+    let mut a = vec![1, 2, 3];
+    let mut x = 0;
+
+    thread::scope(|s| {
+        s.spawn(|| {
+            // We can borrow `a` here.
+            let _s = format!("hello from the first scoped thread: {a:?}");
+        });
+        s.spawn(|| {
+            let _s = format!("hello from the second scoped thread");
+            // We can even mutably borrow `x` here,
+            // because no other threads are using it.
+            x += a[0] + a[2];
+        });
+        let _s = format!("hello from the main thread");
+    });
+
+    // After the scope, we can modify and access our variables again:
+    a.push(4);
+    assert_eq!(x, a.len());
+}
diff --git a/src/tools/miri/tests/pass/stacked-borrows/future-self-referential.rs b/src/tools/miri/tests/pass/stacked-borrows/future-self-referential.rs
new file mode 100644 (file)
index 0000000..3ba2155
--- /dev/null
@@ -0,0 +1,102 @@
+#![feature(pin_macro)]
+
+use std::future::*;
+use std::marker::PhantomPinned;
+use std::pin::*;
+use std::ptr;
+use std::task::*;
+
+struct Delay {
+    delay: usize,
+}
+
+impl Delay {
+    fn new(delay: usize) -> Self {
+        Delay { delay }
+    }
+}
+
+impl Future for Delay {
+    type Output = ();
+    fn poll(mut self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<()> {
+        if self.delay > 0 {
+            self.delay -= 1;
+            Poll::Pending
+        } else {
+            Poll::Ready(())
+        }
+    }
+}
+
+async fn do_stuff() {
+    (&mut Delay::new(1)).await;
+}
+
+// Same thing implemented by hand
+struct DoStuff {
+    state: usize,
+    delay: Delay,
+    delay_ref: *mut Delay,
+    _marker: PhantomPinned,
+}
+
+impl DoStuff {
+    fn new() -> Self {
+        DoStuff {
+            state: 0,
+            delay: Delay::new(1),
+            delay_ref: ptr::null_mut(),
+            _marker: PhantomPinned,
+        }
+    }
+}
+
+impl Future for DoStuff {
+    type Output = ();
+    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<()> {
+        unsafe {
+            let this = self.get_unchecked_mut();
+            match this.state {
+                0 => {
+                    // Set up self-ref.
+                    this.delay_ref = &mut this.delay;
+                    // Move to next state.
+                    this.state = 1;
+                    Poll::Pending
+                }
+                1 => {
+                    let delay = &mut *this.delay_ref;
+                    Pin::new_unchecked(delay).poll(cx)
+                }
+                _ => unreachable!(),
+            }
+        }
+    }
+}
+
+fn run_fut<T>(fut: impl Future<Output = T>) -> T {
+    use std::sync::Arc;
+
+    struct MyWaker;
+    impl Wake for MyWaker {
+        fn wake(self: Arc<Self>) {
+            unimplemented!()
+        }
+    }
+
+    let waker = Waker::from(Arc::new(MyWaker));
+    let mut context = Context::from_waker(&waker);
+
+    let mut pinned = pin!(fut);
+    loop {
+        match pinned.as_mut().poll(&mut context) {
+            Poll::Pending => continue,
+            Poll::Ready(v) => return v,
+        }
+    }
+}
+
+fn main() {
+    run_fut(do_stuff());
+    run_fut(DoStuff::new());
+}
index 423c3a997f53da7e8879bbb797b92a2774026569..244d4427c562359c695f7095ab936cdd3ba3be21 100644 (file)
@@ -335,6 +335,7 @@ pub(crate) fn rewrite_last_closure(
             ref fn_decl,
             ref body,
             fn_decl_span: _,
+            fn_arg_span: _,
         } = **closure;
         let body = match body.kind {
             ast::ExprKind::Block(ref block, _)
index b6530c69243ed1c16c056cffdc358763fb7b8e15..d9dc8d004aff42d4b24eea2c400ca33c6dfecbd1 100644 (file)
@@ -490,7 +490,7 @@ fn from_ast(
                 );
                 result.path.push(UseSegment { kind, version });
             }
-            UseTreeKind::Simple(ref rename, ..) => {
+            UseTreeKind::Simple(ref rename) => {
                 // If the path has leading double colons and is composed of only 2 segments, then we
                 // bypass the call to path_to_imported_ident which would get only the ident and
                 // lose the path root, e.g., `that` in `::that`.
index a7f4016728416b544aa5068d70ff66914768ab1e..7ee8c5d3bad1510fe76e701e8c78671ffbb15a9d 100644 (file)
 /// tooling. It is _crucial_ that no exception crates be dependencies
 /// of the Rust runtime (std/test).
 const EXCEPTIONS: &[(&str, &str)] = &[
-    ("mdbook", "MPL-2.0"),            // mdbook
-    ("openssl", "Apache-2.0"),        // cargo, mdbook
-    ("colored", "MPL-2.0"),           // rustfmt
-    ("ryu", "Apache-2.0 OR BSL-1.0"), // cargo/... (because of serde)
-    ("bytesize", "Apache-2.0"),       // cargo
-    ("im-rc", "MPL-2.0+"),            // cargo
-    ("sized-chunks", "MPL-2.0+"),     // cargo via im-rc
-    ("bitmaps", "MPL-2.0+"),          // cargo via im-rc
-    ("instant", "BSD-3-Clause"),      // rustc_driver/tracing-subscriber/parking_lot
-    ("snap", "BSD-3-Clause"),         // rustc
+    ("ar_archive_writer", "Apache-2.0 WITH LLVM-exception"), // rustc
+    ("mdbook", "MPL-2.0"),                                   // mdbook
+    ("openssl", "Apache-2.0"),                               // cargo, mdbook
+    ("colored", "MPL-2.0"),                                  // rustfmt
+    ("ryu", "Apache-2.0 OR BSL-1.0"),                        // cargo/... (because of serde)
+    ("bytesize", "Apache-2.0"),                              // cargo
+    ("im-rc", "MPL-2.0+"),                                   // cargo
+    ("sized-chunks", "MPL-2.0+"),                            // cargo via im-rc
+    ("bitmaps", "MPL-2.0+"),                                 // cargo via im-rc
+    ("instant", "BSD-3-Clause"), // rustc_driver/tracing-subscriber/parking_lot
+    ("snap", "BSD-3-Clause"),    // rustc
     ("fluent-langneg", "Apache-2.0"), // rustc (fluent translations)
-    ("self_cell", "Apache-2.0"),      // rustc (fluent translations)
+    ("self_cell", "Apache-2.0"), // rustc (fluent translations)
     // FIXME: this dependency violates the documentation comment above:
     ("fortanix-sgx-abi", "MPL-2.0"), // libstd but only for `sgx` target
     ("dunce", "CC0-1.0"),            // cargo (dev dependency)
     ("similar", "Apache-2.0"),       // cargo (dev dependency)
     ("normalize-line-endings", "Apache-2.0"), // cargo (dev dependency)
+    ("dissimilar", "Apache-2.0"),    // rustdoc, rustc_lexer (few tests) via expect-test, (dev deps)
 ];
 
 const EXCEPTIONS_CRANELIFT: &[(&str, &str)] = &[
@@ -86,6 +88,7 @@
     "aho-corasick",
     "annotate-snippets",
     "ansi_term",
+    "ar_archive_writer",
     "arrayvec",
     "atty",
     "autocfg",
     "cstr",
     "datafrog",
     "derive_more",
-    "difference",
     "digest",
     "displaydoc",
+    "dissimilar",
     "dlmalloc",
     "either",
     "ena",
     "snap",
     "stable_deref_trait",
     "stacker",
+    "static_assertions",
     "syn",
     "synstructure",
     "tempfile",
     "tracing-log",
     "tracing-subscriber",
     "tracing-tree",
+    "twox-hash",
     "type-map",
     "typenum",
     "unic-char-property",
 const PERMITTED_CRANELIFT_DEPENDENCIES: &[&str] = &[
     "ahash",
     "anyhow",
-    "ar",
     "arrayvec",
     "autocfg",
     "bumpalo",
index 65ee0959841f14d2e0a0fc971df20d8e761d6e8d..ee2f4ca913048744aab4763a96594995e832c29a 100644 (file)
@@ -1 +1 @@
-1.67.0
+1.68.0
index bc0b88b2babd23256cad271bdf096d082f3eb284..19e8334fc1aa30bf5d753edb1e5b8a94016824e2 100644 (file)
@@ -331,8 +331,16 @@ message = "Some changes occurred to MIR optimizations"
 cc = ["@rust-lang/wg-mir-opt"]
 
 [mentions."compiler/rustc_trait_selection/src/traits/const_evaluatable.rs"]
-message = "Some changes occurred in const_evaluatable.rs"
-cc = ["@lcnr"]
+message = "Some changes occurred in `const_evaluatable.rs`"
+cc = ["@BoxyUwU"]
+
+[mentions."compiler/rustc_middle/src/ty/abstract_const.rs"]
+message = "Some changes occured in `abstract_const.rs`"
+cc = ["@BoxyUwU"]
+
+[mentions."compiler/rustc_ty_utils/src/consts.rs"]
+message = "Some changes occured in `rustc_ty_utils::consts.rs`"
+cc = ["@BoxyUwU"]
 
 [mentions."compiler/rustc_trait_selection/src/traits/engine.rs"]
 message = """
@@ -461,6 +469,7 @@ compiler-team-contributors = [
     "@jackh726",
     "@fee1-dead",
     "@TaKO8Ki",
+    "@Nilstrieb",
 ]
 compiler = [
     "compiler-team",