]> git.lizzy.rs Git - rust.git/commitdiff
Rollup merge of #106856 - vadorovsky:fix-atomic-annotations, r=joshtriplett
authorYuki Okushi <jtitor@2k36.org>
Fri, 27 Jan 2023 03:57:54 +0000 (12:57 +0900)
committerGitHub <noreply@github.com>
Fri, 27 Jan 2023 03:57:54 +0000 (12:57 +0900)
core: Support variety of atomic widths in width-agnostic functions

Before this change, the following functions and macros were annotated with `#[cfg(target_has_atomic = "8")]` or
`#[cfg(target_has_atomic_load_store = "8")]`:

* `atomic_int`
* `strongest_failure_ordering`
* `atomic_swap`
* `atomic_add`
* `atomic_sub`
* `atomic_compare_exchange`
* `atomic_compare_exchange_weak`
* `atomic_and`
* `atomic_nand`
* `atomic_or`
* `atomic_xor`
* `atomic_max`
* `atomic_min`
* `atomic_umax`
* `atomic_umin`

However, none of those functions and macros actually depend on 8-bit width and they are needed for all atomic widths (16-bit, 32-bit, 64-bit etc.). Some targets might not support 8-bit atomics (i.e. BPF, if we would enable atomic CAS for it).

This change fixes that by removing the `"8"` argument from annotations, which results in accepting the whole variety of widths.

Fixes #106845
Fixes #106795

Signed-off-by: Michal Rostecki <vadorovsky@gmail.com>
697 files changed:
Cargo.lock
RELEASES.md
compiler/rustc_abi/src/lib.rs
compiler/rustc_ast/src/ast.rs
compiler/rustc_ast/src/format.rs [new file with mode: 0644]
compiler/rustc_ast/src/lib.rs
compiler/rustc_ast/src/mut_visit.rs
compiler/rustc_ast/src/util/parser.rs
compiler/rustc_ast/src/visit.rs
compiler/rustc_ast_lowering/src/expr.rs
compiler/rustc_ast_lowering/src/format.rs [new file with mode: 0644]
compiler/rustc_ast_lowering/src/lib.rs
compiler/rustc_ast_pretty/Cargo.toml
compiler/rustc_ast_pretty/src/pprust/state/expr.rs
compiler/rustc_borrowck/src/borrowck_errors.rs
compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs
compiler/rustc_borrowck/src/diagnostics/move_errors.rs
compiler/rustc_borrowck/src/diagnostics/region_errors.rs
compiler/rustc_borrowck/src/region_infer/mod.rs
compiler/rustc_borrowck/src/region_infer/opaque_types.rs
compiler/rustc_builtin_macros/src/assert/context.rs
compiler/rustc_builtin_macros/src/format.rs
compiler/rustc_builtin_macros/src/format/ast.rs [deleted file]
compiler/rustc_builtin_macros/src/format/expand.rs [deleted file]
compiler/rustc_codegen_cranelift/.cirrus.yml
compiler/rustc_codegen_cranelift/.github/workflows/main.yml
compiler/rustc_codegen_cranelift/.github/workflows/nightly-cranelift.yml [deleted file]
compiler/rustc_codegen_cranelift/.github/workflows/rustc.yml
compiler/rustc_codegen_cranelift/.gitignore
compiler/rustc_codegen_cranelift/.vscode/settings.json
compiler/rustc_codegen_cranelift/Cargo.lock
compiler/rustc_codegen_cranelift/Cargo.toml
compiler/rustc_codegen_cranelift/Readme.md
compiler/rustc_codegen_cranelift/build_sysroot/Cargo.lock
compiler/rustc_codegen_cranelift/build_system/abi_cafe.rs
compiler/rustc_codegen_cranelift/build_system/bench.rs [new file with mode: 0644]
compiler/rustc_codegen_cranelift/build_system/build_backend.rs
compiler/rustc_codegen_cranelift/build_system/build_sysroot.rs
compiler/rustc_codegen_cranelift/build_system/mod.rs
compiler/rustc_codegen_cranelift/build_system/path.rs
compiler/rustc_codegen_cranelift/build_system/prepare.rs
compiler/rustc_codegen_cranelift/build_system/rustc_info.rs
compiler/rustc_codegen_cranelift/build_system/tests.rs
compiler/rustc_codegen_cranelift/build_system/usage.txt [new file with mode: 0644]
compiler/rustc_codegen_cranelift/build_system/utils.rs
compiler/rustc_codegen_cranelift/clean_all.sh
compiler/rustc_codegen_cranelift/config.txt
compiler/rustc_codegen_cranelift/patches/0001-portable-simd-Disable-unsupported-tests.patch [deleted file]
compiler/rustc_codegen_cranelift/patches/0022-sysroot-Disable-not-compiling-tests.patch
compiler/rustc_codegen_cranelift/rust-toolchain
compiler/rustc_codegen_cranelift/scripts/cargo-clif.rs
compiler/rustc_codegen_cranelift/scripts/rustc-clif.rs
compiler/rustc_codegen_cranelift/scripts/rustdoc-clif.rs
compiler/rustc_codegen_cranelift/scripts/rustup.sh
compiler/rustc_codegen_cranelift/scripts/setup_rust_fork.sh
compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh
compiler/rustc_codegen_cranelift/src/abi/mod.rs
compiler/rustc_codegen_cranelift/src/base.rs
compiler/rustc_codegen_cranelift/src/common.rs
compiler/rustc_codegen_cranelift/src/cranelift_native.rs [new file with mode: 0644]
compiler/rustc_codegen_cranelift/src/debuginfo/mod.rs
compiler/rustc_codegen_cranelift/src/driver/aot.rs
compiler/rustc_codegen_cranelift/src/intrinsics/llvm_x86.rs
compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs
compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs
compiler/rustc_codegen_cranelift/src/lib.rs
compiler/rustc_codegen_cranelift/src/main_shim.rs
compiler/rustc_codegen_cranelift/src/optimize/peephole.rs
compiler/rustc_codegen_cranelift/src/value_and_place.rs
compiler/rustc_codegen_cranelift/y.rs
compiler/rustc_codegen_gcc/src/builder.rs
compiler/rustc_codegen_gcc/src/common.rs
compiler/rustc_codegen_gcc/src/consts.rs
compiler/rustc_codegen_gcc/src/type_of.rs
compiler/rustc_codegen_llvm/src/asm.rs
compiler/rustc_codegen_llvm/src/builder.rs
compiler/rustc_codegen_llvm/src/common.rs
compiler/rustc_codegen_llvm/src/consts.rs
compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs
compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/mod.rs
compiler/rustc_codegen_llvm/src/errors.rs
compiler/rustc_codegen_llvm/src/intrinsic.rs
compiler/rustc_codegen_llvm/src/type_of.rs
compiler/rustc_codegen_ssa/src/back/link.rs
compiler/rustc_codegen_ssa/src/mir/block.rs
compiler/rustc_codegen_ssa/src/mir/place.rs
compiler/rustc_const_eval/src/interpret/intrinsics.rs
compiler/rustc_const_eval/src/interpret/operand.rs
compiler/rustc_const_eval/src/lib.rs
compiler/rustc_const_eval/src/transform/check_consts/check.rs
compiler/rustc_const_eval/src/transform/validate.rs
compiler/rustc_const_eval/src/util/might_permit_raw_init.rs
compiler/rustc_data_structures/src/obligation_forest/mod.rs
compiler/rustc_driver/src/lib.rs
compiler/rustc_driver/src/pretty.rs
compiler/rustc_error_messages/locales/en-US/borrowck.ftl
compiler/rustc_error_messages/locales/en-US/codegen_llvm.ftl
compiler/rustc_error_messages/locales/en-US/infer.ftl
compiler/rustc_error_messages/locales/en-US/mir_build.ftl
compiler/rustc_error_messages/locales/en-US/parse.ftl
compiler/rustc_error_messages/locales/en-US/passes.ftl
compiler/rustc_error_messages/src/lib.rs
compiler/rustc_feature/src/lib.rs
compiler/rustc_hir/src/hir.rs
compiler/rustc_hir/src/lang_items.rs
compiler/rustc_hir_analysis/src/autoderef.rs
compiler/rustc_hir_analysis/src/check/check.rs
compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
compiler/rustc_hir_analysis/src/check/intrinsic.rs
compiler/rustc_hir_analysis/src/check/wfcheck.rs
compiler/rustc_hir_analysis/src/coherence/builtin.rs
compiler/rustc_hir_analysis/src/collect.rs
compiler/rustc_hir_analysis/src/hir_wf_check.rs
compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs
compiler/rustc_hir_analysis/src/lib.rs
compiler/rustc_hir_typeck/src/_match.rs
compiler/rustc_hir_typeck/src/check.rs
compiler/rustc_hir_typeck/src/closure.rs
compiler/rustc_hir_typeck/src/coercion.rs
compiler/rustc_hir_typeck/src/demand.rs
compiler/rustc_hir_typeck/src/expr.rs
compiler/rustc_hir_typeck/src/fn_ctxt/_impl.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/intrinsicck.rs
compiler/rustc_hir_typeck/src/lib.rs
compiler/rustc_hir_typeck/src/method/probe.rs
compiler/rustc_hir_typeck/src/method/suggest.rs
compiler/rustc_infer/src/infer/error_reporting/mod.rs
compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs [new file with mode: 0644]
compiler/rustc_infer/src/infer/error_reporting/suggest.rs
compiler/rustc_infer/src/infer/opaque_types.rs
compiler/rustc_infer/src/traits/mod.rs
compiler/rustc_interface/src/passes.rs
compiler/rustc_interface/src/queries.rs
compiler/rustc_lint/src/builtin.rs
compiler/rustc_lint/src/for_loops_over_fallibles.rs
compiler/rustc_metadata/src/rmeta/decoder.rs
compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
compiler/rustc_metadata/src/rmeta/encoder.rs
compiler/rustc_metadata/src/rmeta/mod.rs
compiler/rustc_metadata/src/rmeta/table.rs
compiler/rustc_middle/src/lib.rs
compiler/rustc_middle/src/mir/interpret/mod.rs
compiler/rustc_middle/src/query/mod.rs
compiler/rustc_middle/src/traits/mod.rs
compiler/rustc_middle/src/ty/assoc.rs
compiler/rustc_middle/src/ty/context.rs
compiler/rustc_middle/src/ty/context/tls.rs [new file with mode: 0644]
compiler/rustc_middle/src/ty/error.rs
compiler/rustc_middle/src/ty/layout.rs
compiler/rustc_middle/src/ty/mod.rs
compiler/rustc_middle/src/ty/query.rs
compiler/rustc_middle/src/ty/structural_impls.rs
compiler/rustc_middle/src/ty/util.rs
compiler/rustc_mir_build/src/build/custom/parse/instruction.rs
compiler/rustc_mir_build/src/errors.rs
compiler/rustc_mir_build/src/thir/pattern/check_match.rs
compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs
compiler/rustc_mir_transform/src/const_goto.rs
compiler/rustc_mir_transform/src/instcombine.rs
compiler/rustc_mir_transform/src/lib.rs
compiler/rustc_mir_transform/src/simplify_try.rs [deleted file]
compiler/rustc_parse/src/errors.rs
compiler/rustc_parse/src/parser/diagnostics.rs
compiler/rustc_parse/src/parser/expr.rs
compiler/rustc_parse/src/parser/pat.rs
compiler/rustc_parse/src/parser/ty.rs
compiler/rustc_passes/src/check_attr.rs
compiler/rustc_passes/src/check_const.rs
compiler/rustc_passes/src/errors.rs
compiler/rustc_passes/src/hir_stats.rs
compiler/rustc_resolve/src/late/diagnostics.rs
compiler/rustc_session/src/config.rs
compiler/rustc_span/src/symbol.rs
compiler/rustc_target/src/abi/call/loongarch.rs
compiler/rustc_target/src/abi/call/mod.rs
compiler/rustc_target/src/abi/call/riscv.rs
compiler/rustc_target/src/abi/call/sparc64.rs
compiler/rustc_target/src/abi/call/x86_64.rs
compiler/rustc_target/src/abi/mod.rs
compiler/rustc_trait_selection/src/solve/assembly.rs
compiler/rustc_trait_selection/src/solve/fulfill.rs
compiler/rustc_trait_selection/src/solve/mod.rs
compiler/rustc_trait_selection/src/solve/project_goals.rs
compiler/rustc_trait_selection/src/solve/trait_goals.rs
compiler/rustc_trait_selection/src/solve/trait_goals/structural_traits.rs
compiler/rustc_trait_selection/src/traits/coherence.rs
compiler/rustc_trait_selection/src/traits/engine.rs
compiler/rustc_trait_selection/src/traits/error_reporting/ambiguity.rs
compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs
compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
compiler/rustc_trait_selection/src/traits/mod.rs
compiler/rustc_trait_selection/src/traits/outlives_bounds.rs
compiler/rustc_trait_selection/src/traits/wf.rs
compiler/rustc_traits/src/implied_outlives_bounds.rs
compiler/rustc_traits/src/type_op.rs
compiler/rustc_ty_utils/src/abi.rs
compiler/rustc_ty_utils/src/layout.rs
compiler/rustc_ty_utils/src/ty.rs
library/core/src/cell.rs
library/core/src/cell/once.rs
library/core/src/fmt/mod.rs
library/core/src/fmt/rt/v1.rs
library/core/src/intrinsics/mir.rs
library/core/src/marker.rs
library/core/src/ptr/const_ptr.rs
library/core/src/ptr/mut_ptr.rs
library/proc_macro/src/lib.rs
library/std/src/sync/mpmc/array.rs
library/std/src/sync/mpmc/utils.rs
library/std/src/sys/unix/thread_local_dtor.rs
library/std/tests/run-time-detect.rs
library/stdarch
library/test/src/cli.rs
src/bootstrap/bin/main.rs
src/bootstrap/dist.rs
src/librustdoc/html/format.rs
src/librustdoc/html/static/css/rustdoc.css
src/librustdoc/html/static/css/settings.css
src/librustdoc/html/static/js/settings.js
src/librustdoc/lib.rs
src/tools/cargo
src/tools/clippy/clippy_lints/src/format_args.rs
src/tools/clippy/clippy_lints/src/future_not_send.rs
src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs
src/tools/clippy/clippy_lints/src/transmute/utils.rs
src/tools/clippy/clippy_utils/src/macros.rs
src/tools/clippy/clippy_utils/src/sugg.rs
src/tools/rustfmt/.github/workflows/check_diff.yml [new file with mode: 0644]
src/tools/rustfmt/.github/workflows/integration.yml
src/tools/rustfmt/CHANGELOG.md
src/tools/rustfmt/Cargo.lock
src/tools/rustfmt/Cargo.toml
src/tools/rustfmt/Configurations.md
src/tools/rustfmt/Processes.md
src/tools/rustfmt/ci/build_and_test.bat
src/tools/rustfmt/ci/build_and_test.sh
src/tools/rustfmt/ci/check_diff.sh [new file with mode: 0755]
src/tools/rustfmt/ci/integration.sh
src/tools/rustfmt/config_proc_macro/Cargo.lock
src/tools/rustfmt/config_proc_macro/Cargo.toml
src/tools/rustfmt/config_proc_macro/src/attrs.rs
src/tools/rustfmt/config_proc_macro/src/item_enum.rs
src/tools/rustfmt/config_proc_macro/src/lib.rs
src/tools/rustfmt/config_proc_macro/tests/smoke.rs
src/tools/rustfmt/rust-toolchain
src/tools/rustfmt/src/attr.rs
src/tools/rustfmt/src/bin/main.rs
src/tools/rustfmt/src/cargo-fmt/main.rs
src/tools/rustfmt/src/cargo-fmt/test/mod.rs
src/tools/rustfmt/src/chains.rs
src/tools/rustfmt/src/config/config_type.rs
src/tools/rustfmt/src/config/macro_names.rs [new file with mode: 0644]
src/tools/rustfmt/src/config/mod.rs
src/tools/rustfmt/src/expr.rs
src/tools/rustfmt/src/imports.rs
src/tools/rustfmt/src/items.rs
src/tools/rustfmt/src/lists.rs
src/tools/rustfmt/src/macros.rs
src/tools/rustfmt/src/skip.rs
src/tools/rustfmt/src/test/configuration_snippet.rs
src/tools/rustfmt/src/test/mod.rs
src/tools/rustfmt/src/types.rs
src/tools/rustfmt/src/utils.rs
src/tools/rustfmt/src/visitor.rs
src/tools/rustfmt/tests/cargo-fmt/main.rs
src/tools/rustfmt/tests/cargo-fmt/source/issue_3164/Cargo.toml [new file with mode: 0644]
src/tools/rustfmt/tests/cargo-fmt/source/issue_3164/src/main.rs [new file with mode: 0644]
src/tools/rustfmt/tests/config/small_tabs.toml
src/tools/rustfmt/tests/mod-resolver/issue-5198/lib/c/d/explanation.txt
src/tools/rustfmt/tests/mod-resolver/issue-5198/lib/explanation.txt
src/tools/rustfmt/tests/rustfmt/main.rs
src/tools/rustfmt/tests/source/cfg_if/detect/arch/x86.rs
src/tools/rustfmt/tests/source/comments_unicode.rs [new file with mode: 0644]
src/tools/rustfmt/tests/source/configs/fn_args_layout/compressed.rs [deleted file]
src/tools/rustfmt/tests/source/configs/fn_args_layout/tall.rs [deleted file]
src/tools/rustfmt/tests/source/configs/fn_args_layout/vertical.rs [deleted file]
src/tools/rustfmt/tests/source/configs/fn_params_layout/compressed.rs [new file with mode: 0644]
src/tools/rustfmt/tests/source/configs/fn_params_layout/tall.rs [new file with mode: 0644]
src/tools/rustfmt/tests/source/configs/fn_params_layout/vertical.rs [new file with mode: 0644]
src/tools/rustfmt/tests/source/enum.rs
src/tools/rustfmt/tests/source/fn-custom-7.rs
src/tools/rustfmt/tests/source/fn-custom.rs
src/tools/rustfmt/tests/source/fn_args_layout-vertical.rs
src/tools/rustfmt/tests/source/issue-3987/format_macro_bodies_true.rs [new file with mode: 0644]
src/tools/rustfmt/tests/source/issue-4643.rs [new file with mode: 0644]
src/tools/rustfmt/tests/source/issue-4689/one.rs [new file with mode: 0644]
src/tools/rustfmt/tests/source/issue-4689/two.rs [new file with mode: 0644]
src/tools/rustfmt/tests/source/issue_1306.rs [new file with mode: 0644]
src/tools/rustfmt/tests/source/issue_3245.rs [new file with mode: 0644]
src/tools/rustfmt/tests/source/issue_3561.rs [new file with mode: 0644]
src/tools/rustfmt/tests/source/skip_macro_invocations/all.rs [new file with mode: 0644]
src/tools/rustfmt/tests/source/skip_macro_invocations/all_and_name.rs [new file with mode: 0644]
src/tools/rustfmt/tests/source/skip_macro_invocations/empty.rs [new file with mode: 0644]
src/tools/rustfmt/tests/source/skip_macro_invocations/name.rs [new file with mode: 0644]
src/tools/rustfmt/tests/source/skip_macro_invocations/name_unknown.rs [new file with mode: 0644]
src/tools/rustfmt/tests/source/skip_macro_invocations/names.rs [new file with mode: 0644]
src/tools/rustfmt/tests/source/skip_macro_invocations/path_qualified_invocation_mismatch.rs [new file with mode: 0644]
src/tools/rustfmt/tests/source/skip_macro_invocations/path_qualified_match.rs [new file with mode: 0644]
src/tools/rustfmt/tests/source/skip_macro_invocations/path_qualified_name_mismatch.rs [new file with mode: 0644]
src/tools/rustfmt/tests/source/skip_macro_invocations/use_alias_examples.rs [new file with mode: 0644]
src/tools/rustfmt/tests/source/tuple.rs
src/tools/rustfmt/tests/source/wrap_comments_should_not_imply_format_doc_comments.rs
src/tools/rustfmt/tests/target/cfg_if/detect/arch/x86.rs
src/tools/rustfmt/tests/target/comments_unicode.rs [new file with mode: 0644]
src/tools/rustfmt/tests/target/configs/fn_args_layout/compressed.rs [deleted file]
src/tools/rustfmt/tests/target/configs/fn_args_layout/tall.rs [deleted file]
src/tools/rustfmt/tests/target/configs/fn_args_layout/vertical.rs [deleted file]
src/tools/rustfmt/tests/target/configs/fn_params_layout/compressed.rs [new file with mode: 0644]
src/tools/rustfmt/tests/target/configs/fn_params_layout/tall.rs [new file with mode: 0644]
src/tools/rustfmt/tests/target/configs/fn_params_layout/vertical.rs [new file with mode: 0644]
src/tools/rustfmt/tests/target/enum.rs
src/tools/rustfmt/tests/target/fn-custom-7.rs
src/tools/rustfmt/tests/target/fn-custom.rs
src/tools/rustfmt/tests/target/fn_args_layout-vertical.rs
src/tools/rustfmt/tests/target/issue-2534/format_macro_matchers_false.rs [new file with mode: 0644]
src/tools/rustfmt/tests/target/issue-2534/format_macro_matchers_true.rs [new file with mode: 0644]
src/tools/rustfmt/tests/target/issue-3987/format_macro_bodies_false.rs [new file with mode: 0644]
src/tools/rustfmt/tests/target/issue-3987/format_macro_bodies_true.rs [new file with mode: 0644]
src/tools/rustfmt/tests/target/issue-4643.rs [new file with mode: 0644]
src/tools/rustfmt/tests/target/issue-4689/one.rs [new file with mode: 0644]
src/tools/rustfmt/tests/target/issue-4689/two.rs [new file with mode: 0644]
src/tools/rustfmt/tests/target/issue-4791/issue_4928.rs
src/tools/rustfmt/tests/target/issue-5358.rs [new file with mode: 0644]
src/tools/rustfmt/tests/target/issue_1306.rs [new file with mode: 0644]
src/tools/rustfmt/tests/target/issue_3033.rs [new file with mode: 0644]
src/tools/rustfmt/tests/target/issue_3245.rs [new file with mode: 0644]
src/tools/rustfmt/tests/target/issue_3561.rs [new file with mode: 0644]
src/tools/rustfmt/tests/target/issue_4350.rs [new file with mode: 0644]
src/tools/rustfmt/tests/target/issue_5668.rs [new file with mode: 0644]
src/tools/rustfmt/tests/target/skip_macro_invocations/all.rs [new file with mode: 0644]
src/tools/rustfmt/tests/target/skip_macro_invocations/all_and_name.rs [new file with mode: 0644]
src/tools/rustfmt/tests/target/skip_macro_invocations/empty.rs [new file with mode: 0644]
src/tools/rustfmt/tests/target/skip_macro_invocations/name.rs [new file with mode: 0644]
src/tools/rustfmt/tests/target/skip_macro_invocations/name_unknown.rs [new file with mode: 0644]
src/tools/rustfmt/tests/target/skip_macro_invocations/names.rs [new file with mode: 0644]
src/tools/rustfmt/tests/target/skip_macro_invocations/path_qualified_invocation_mismatch.rs [new file with mode: 0644]
src/tools/rustfmt/tests/target/skip_macro_invocations/path_qualified_match.rs [new file with mode: 0644]
src/tools/rustfmt/tests/target/skip_macro_invocations/path_qualified_name_mismatch.rs [new file with mode: 0644]
src/tools/rustfmt/tests/target/skip_macro_invocations/use_alias_examples.rs [new file with mode: 0644]
src/tools/rustfmt/tests/target/tuple.rs
src/tools/rustfmt/tests/target/wrap_comments_should_not_imply_format_doc_comments.rs
src/tools/tidy/src/deps.rs
tests/codegen/avr/avr-func-addrspace.rs
tests/mir-opt/76803_regression.encode.SimplifyBranchSame.diff [deleted file]
tests/mir-opt/76803_regression.rs [deleted file]
tests/mir-opt/building/custom/arrays.arrays.built.after.mir [new file with mode: 0644]
tests/mir-opt/building/custom/arrays.rs [new file with mode: 0644]
tests/mir-opt/building/custom/enums.rs
tests/mir-opt/building/custom/enums.set_discr.built.after.mir
tests/mir-opt/building/custom/operators.f.built.after.mir [new file with mode: 0644]
tests/mir-opt/building/custom/operators.rs [new file with mode: 0644]
tests/mir-opt/intrinsic_asserts.generic.InstCombine.diff [new file with mode: 0644]
tests/mir-opt/intrinsic_asserts.panics.InstCombine.diff [new file with mode: 0644]
tests/mir-opt/intrinsic_asserts.removable.InstCombine.diff [new file with mode: 0644]
tests/mir-opt/intrinsic_asserts.rs [new file with mode: 0644]
tests/mir-opt/issue_73223.main.SimplifyArmIdentity.diff [deleted file]
tests/mir-opt/issue_73223.rs [deleted file]
tests/pretty/dollar-crate.pp
tests/pretty/issue-4264.pp
tests/run-make-fulldeps/split-debuginfo/Makefile
tests/run-make/overwrite-input/Makefile [new file with mode: 0644]
tests/run-make/overwrite-input/file.stderr [new file with mode: 0644]
tests/run-make/overwrite-input/folder.stderr [new file with mode: 0644]
tests/run-make/overwrite-input/main.rs [new file with mode: 0644]
tests/run-make/overwrite-input/main.stderr [new file with mode: 0644]
tests/rustdoc-gui/mobile.goml
tests/rustdoc-gui/settings.goml
tests/rustdoc-gui/theme-change.goml
tests/rustdoc/whitespace-after-where-clause.enum.html
tests/rustdoc/whitespace-after-where-clause.enum2.html
tests/rustdoc/whitespace-after-where-clause.struct.html
tests/rustdoc/whitespace-after-where-clause.struct2.html
tests/ui-fulldeps/dropck-tarena-cycle-checked.stderr
tests/ui-fulldeps/dropck-tarena-unsound-drop.stderr
tests/ui/asm/type-check-4.stderr
tests/ui/associated-types/associated-types-outlives.stderr
tests/ui/associated-types/defaults-in-other-trait-items.rs
tests/ui/associated-types/defaults-in-other-trait-items.stderr
tests/ui/associated-types/issue-26681.stderr
tests/ui/async-await/issue-68112.drop_tracking.stderr
tests/ui/async-await/issue-68112.no_drop_tracking.stderr
tests/ui/async-await/issue-74072-lifetime-name-annotations.stderr
tests/ui/async-await/issue-75785-confusing-named-region.stderr
tests/ui/async-await/multiple-lifetimes/ret-ref.stderr
tests/ui/attributes/key-value-expansion.stderr
tests/ui/augmented-assignments.rs
tests/ui/augmented-assignments.stderr
tests/ui/binop/binop-move-semantics.stderr
tests/ui/borrowck/bindings-after-at-or-patterns-slice-patterns-box-patterns.stderr
tests/ui/borrowck/borrow-tuple-fields.stderr
tests/ui/borrowck/borrowck-anon-fields-variant.stderr
tests/ui/borrowck/borrowck-assign-comp.stderr
tests/ui/borrowck/borrowck-assign-to-andmut-in-borrowed-loc.stderr
tests/ui/borrowck/borrowck-bad-nested-calls-move.stderr
tests/ui/borrowck/borrowck-closures-mut-and-imm.stderr
tests/ui/borrowck/borrowck-describe-lvalue.stderr
tests/ui/borrowck/borrowck-field-sensitivity.stderr
tests/ui/borrowck/borrowck-imm-ref-to-mut-rec-field-issue-3162-c.stderr
tests/ui/borrowck/borrowck-issue-14498.stderr
tests/ui/borrowck/borrowck-lend-flow-match.stderr
tests/ui/borrowck/borrowck-loan-blocks-move-cc.stderr
tests/ui/borrowck/borrowck-loan-blocks-move.stderr
tests/ui/borrowck/borrowck-loan-of-static-data-issue-27616.stderr
tests/ui/borrowck/borrowck-loan-rcvr-overloaded-op.stderr
tests/ui/borrowck/borrowck-local-borrow-with-panic-outlives-fn.stderr
tests/ui/borrowck/borrowck-match-already-borrowed.stderr
tests/ui/borrowck/borrowck-move-by-capture.stderr
tests/ui/borrowck/borrowck-move-from-subpath-of-borrowed-path.stderr
tests/ui/borrowck/borrowck-move-mut-base-ptr.stderr
tests/ui/borrowck/borrowck-move-subcomponent.stderr
tests/ui/borrowck/borrowck-multiple-captures.stderr
tests/ui/borrowck/borrowck-overloaded-index-and-overloaded-deref.stderr
tests/ui/borrowck/borrowck-overloaded-index-autoderef.stderr
tests/ui/borrowck/borrowck-overloaded-index-move-index.stderr
tests/ui/borrowck/borrowck-pat-reassign-binding.stderr
tests/ui/borrowck/borrowck-unary-move.stderr
tests/ui/borrowck/borrowck-union-borrow-nested.stderr
tests/ui/borrowck/borrowck-union-borrow.stderr
tests/ui/borrowck/borrowck-use-mut-borrow.stderr
tests/ui/borrowck/borrowck-vec-pattern-move-tail.stderr
tests/ui/borrowck/borrowck-vec-pattern-nesting.rs
tests/ui/borrowck/borrowck-vec-pattern-nesting.stderr
tests/ui/borrowck/issue-25793.stderr
tests/ui/borrowck/issue-52713-bug.stderr
tests/ui/borrowck/issue-58776-borrowck-scans-children.stderr
tests/ui/borrowck/issue-81365-1.stderr
tests/ui/borrowck/issue-81365-10.stderr
tests/ui/borrowck/issue-81365-11.stderr
tests/ui/borrowck/issue-81365-2.stderr
tests/ui/borrowck/issue-81365-3.stderr
tests/ui/borrowck/issue-81365-4.stderr
tests/ui/borrowck/issue-81365-5.stderr
tests/ui/borrowck/issue-81365-6.stderr
tests/ui/borrowck/issue-81365-7.stderr
tests/ui/borrowck/issue-81365-8.stderr
tests/ui/borrowck/issue-81365-9.stderr
tests/ui/borrowck/two-phase-allow-access-during-reservation.nll_target.stderr
tests/ui/borrowck/two-phase-surprise-no-conflict.stderr
tests/ui/box/leak-alloc.stderr
tests/ui/btreemap/btreemap_dropck.stderr
tests/ui/c-variadic/variadic-ffi-4.stderr
tests/ui/closures/2229_closure_analysis/diagnostics/arrays.stderr
tests/ui/closures/2229_closure_analysis/diagnostics/box.stderr
tests/ui/closures/2229_closure_analysis/diagnostics/union.rs
tests/ui/closures/2229_closure_analysis/diagnostics/union.stderr
tests/ui/coercion/coerce-overloaded-autoderef-fail.stderr
tests/ui/consts/promote_const_let.stderr
tests/ui/dropck/drop-with-active-borrows-1.stderr
tests/ui/dropck/dropck-eyepatch-extern-crate.stderr
tests/ui/dropck/dropck-eyepatch-reorder.stderr
tests/ui/dropck/dropck-eyepatch.stderr
tests/ui/dropck/dropck-union.stderr
tests/ui/dropck/dropck_trait_cycle_checked.stderr
tests/ui/dst/dst-bad-coerce3.stderr
tests/ui/error-codes/E0503.stderr
tests/ui/error-codes/E0504.stderr
tests/ui/error-codes/E0505.stderr
tests/ui/error-codes/E0506.stderr
tests/ui/error-codes/E0597.stderr
tests/ui/feature-gates/feature-gate-dispatch-from-dyn-cell.rs [new file with mode: 0644]
tests/ui/feature-gates/feature-gate-dispatch-from-dyn-cell.stderr [new file with mode: 0644]
tests/ui/feature-gates/feature-gate-dispatch-from-dyn-missing-impl.rs [new file with mode: 0644]
tests/ui/feature-gates/feature-gate-dispatch-from-dyn-missing-impl.stderr [new file with mode: 0644]
tests/ui/fn/fn-compare-mismatch.stderr
tests/ui/fn/fn-item-type.rs
tests/ui/fn/fn-item-type.stderr
tests/ui/fn/fn-pointer-mismatch.rs [new file with mode: 0644]
tests/ui/fn/fn-pointer-mismatch.stderr [new file with mode: 0644]
tests/ui/fn/implied-bounds-unnorm-associated-type-4.stderr
tests/ui/fn/implied-bounds-unnorm-associated-type.stderr
tests/ui/generator/dropck.stderr
tests/ui/generator/issue-68112.rs
tests/ui/generator/issue-68112.stderr
tests/ui/generator/not-send-sync.stderr
tests/ui/generator/print/generator-print-verbose-1.stderr
tests/ui/generator/print/generator-print-verbose-2.stderr
tests/ui/generic-associated-types/issue-74684-1.stderr
tests/ui/higher-rank-trait-bounds/hrtb-identity-fn-borrows.stderr
tests/ui/impl-trait/feature-self-return-type.stderr
tests/ui/implied-bounds/assoc-ty-wf-used-to-get-assoc-ty.stderr
tests/ui/inline-const/const-expr-lifetime-err.stderr
tests/ui/io-checks/inaccessbile-temp-dir.rs [new file with mode: 0644]
tests/ui/io-checks/inaccessbile-temp-dir.stderr [new file with mode: 0644]
tests/ui/io-checks/non-ice-error-on-worker-io-fail.rs [new file with mode: 0644]
tests/ui/io-checks/non-ice-error-on-worker-io-fail.stderr [new file with mode: 0644]
tests/ui/issues/issue-40288.stderr
tests/ui/issues/issue-45697-1.stderr
tests/ui/issues/issue-45697.stderr
tests/ui/issues/issue-46471-1.stderr
tests/ui/issues/issue-52126-assign-op-invariance.stderr
tests/ui/issues/issue-7364.stderr
tests/ui/let-else/accidental-if.rs [new file with mode: 0644]
tests/ui/let-else/accidental-if.stderr [new file with mode: 0644]
tests/ui/lifetimes/issue-103582-hint-for-missing-lifetime-bound-on-trait-object-using-type-alias.fixed [new file with mode: 0644]
tests/ui/lifetimes/issue-103582-hint-for-missing-lifetime-bound-on-trait-object-using-type-alias.rs [new file with mode: 0644]
tests/ui/lifetimes/issue-103582-hint-for-missing-lifetime-bound-on-trait-object-using-type-alias.stderr [new file with mode: 0644]
tests/ui/lifetimes/issue-90600-expected-return-static-indirect.stderr
tests/ui/macros/format-args-temporaries-in-write.stderr
tests/ui/macros/rfc-2011-nicer-assert-messages/non-consuming-methods-have-optimized-codegen.stdout
tests/ui/match/issue-74050-end-span.stderr
tests/ui/moves/move-fn-self-receiver.stderr
tests/ui/mut/mut-pattern-internal-mutability.stderr
tests/ui/mutexguard-sync.rs [deleted file]
tests/ui/mutexguard-sync.stderr [deleted file]
tests/ui/nll/borrowed-local-error.stderr
tests/ui/nll/borrowed-match-issue-45045.stderr
tests/ui/nll/capture-ref-in-struct.stderr
tests/ui/nll/closure-access-spans.stderr
tests/ui/nll/closure-borrow-spans.stderr
tests/ui/nll/closure-requirements/escape-argument.stderr
tests/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.stderr
tests/ui/nll/closure-use-spans.stderr
tests/ui/nll/do-not-ignore-lifetime-bounds-in-copy-proj.stderr
tests/ui/nll/do-not-ignore-lifetime-bounds-in-copy.stderr
tests/ui/nll/dont-print-desugared.stderr
tests/ui/nll/drop-no-may-dangle.stderr
tests/ui/nll/guarantor-issue-46974.stderr
tests/ui/nll/issue-27282-move-ref-mut-into-guard.stderr
tests/ui/nll/issue-27282-mutation-in-guard.stderr
tests/ui/nll/issue-27868.stderr
tests/ui/nll/issue-46036.stderr
tests/ui/nll/issue-48803.stderr
tests/ui/nll/issue-52534-2.stderr
tests/ui/nll/issue-52663-trait-object.stderr
tests/ui/nll/issue-54382-use-span-of-tail-of-block.stderr
tests/ui/nll/issue-54556-niconii.stderr
tests/ui/nll/issue-54556-stephaneyfx.stderr
tests/ui/nll/issue-54556-temps-in-tail-diagnostic.stderr
tests/ui/nll/issue-54556-used-vs-unused-tails.stderr
tests/ui/nll/issue-54556-wrap-it-up.stderr
tests/ui/nll/issue-55511.stderr
tests/ui/nll/issue-57989.stderr
tests/ui/nll/issue-68550.stderr
tests/ui/nll/issue-69114-static-mut-ty.stderr
tests/ui/nll/issue-69114-static-ty.stderr
tests/ui/nll/loan_ends_mid_block_pair.stderr
tests/ui/nll/local-outlives-static-via-hrtb.stderr
tests/ui/nll/match-cfg-fake-edges2.stderr
tests/ui/nll/match-guards-always-borrow.stderr
tests/ui/nll/match-guards-partially-borrow.stderr
tests/ui/nll/match-on-borrowed.stderr
tests/ui/nll/maybe-initialized-drop-implicit-fragment-drop.stderr
tests/ui/nll/maybe-initialized-drop-with-fragment.stderr
tests/ui/nll/maybe-initialized-drop-with-uninitialized-fragments.stderr
tests/ui/nll/maybe-initialized-drop.stderr
tests/ui/nll/polonius/polonius-smoke-test.stderr
tests/ui/nll/promoted-bounds.stderr
tests/ui/nll/reference-carried-through-struct-field.stderr
tests/ui/nll/relate_tys/var-appears-twice.stderr
tests/ui/nll/user-annotations/adt-brace-enums.stderr
tests/ui/nll/user-annotations/adt-brace-structs.stderr
tests/ui/nll/user-annotations/adt-nullary-enums.stderr
tests/ui/nll/user-annotations/adt-tuple-enums.stderr
tests/ui/nll/user-annotations/adt-tuple-struct-calls.stderr
tests/ui/nll/user-annotations/adt-tuple-struct.stderr
tests/ui/nll/user-annotations/cast_static_lifetime.stderr
tests/ui/nll/user-annotations/constant-in-expr-inherent-2.stderr
tests/ui/nll/user-annotations/fns.stderr
tests/ui/nll/user-annotations/method-call.stderr
tests/ui/nll/user-annotations/method-ufcs-1.stderr
tests/ui/nll/user-annotations/method-ufcs-2.stderr
tests/ui/nll/user-annotations/method-ufcs-3.stderr
tests/ui/nll/user-annotations/method-ufcs-inherent-1.stderr
tests/ui/nll/user-annotations/method-ufcs-inherent-2.stderr
tests/ui/nll/user-annotations/method-ufcs-inherent-3.stderr
tests/ui/nll/user-annotations/method-ufcs-inherent-4.stderr
tests/ui/nll/user-annotations/normalization.stderr
tests/ui/nll/user-annotations/pattern_substs_on_brace_enum_variant.stderr
tests/ui/nll/user-annotations/pattern_substs_on_brace_struct.stderr
tests/ui/nll/user-annotations/pattern_substs_on_tuple_enum_variant.stderr
tests/ui/nll/user-annotations/pattern_substs_on_tuple_struct.stderr
tests/ui/nll/user-annotations/patterns.stderr
tests/ui/nll/user-annotations/promoted-annotation.stderr
tests/ui/nll/user-annotations/type_ascription_static_lifetime.stderr
tests/ui/non-ice-error-on-worker-io-fail.rs [deleted file]
tests/ui/non-ice-error-on-worker-io-fail.stderr [deleted file]
tests/ui/parser/anon-enums.rs [new file with mode: 0644]
tests/ui/parser/anon-enums.stderr [new file with mode: 0644]
tests/ui/parser/fake-anon-enums-in-macros.rs [new file with mode: 0644]
tests/ui/parser/issues/issue-87086-colon-path-sep.rs
tests/ui/parser/issues/issue-87086-colon-path-sep.stderr
tests/ui/pattern/bindings-after-at/bind-by-move-neither-can-live-while-the-other-survives-1.stderr
tests/ui/pattern/bindings-after-at/borrowck-pat-at-and-box.stderr
tests/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref.stderr
tests/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-and-ref.stderr
tests/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-twice.stderr
tests/ui/pattern/bindings-after-at/default-binding-modes-both-sides-independent.stderr
tests/ui/pattern/move-ref-patterns/borrowck-move-ref-pattern.stderr
tests/ui/proc-macro/allowed-signatures.rs [new file with mode: 0644]
tests/ui/proc-macro/proc-macro-abi.rs [new file with mode: 0644]
tests/ui/proc-macro/proc-macro-abi.stderr [new file with mode: 0644]
tests/ui/proc-macro/signature-proc-macro-attribute.rs [new file with mode: 0644]
tests/ui/proc-macro/signature-proc-macro-attribute.stderr [new file with mode: 0644]
tests/ui/proc-macro/signature-proc-macro-derive.rs [new file with mode: 0644]
tests/ui/proc-macro/signature-proc-macro-derive.stderr [new file with mode: 0644]
tests/ui/proc-macro/signature-proc-macro.rs [new file with mode: 0644]
tests/ui/proc-macro/signature-proc-macro.stderr [new file with mode: 0644]
tests/ui/proc-macro/signature.rs
tests/ui/proc-macro/signature.stderr
tests/ui/regions/do-not-suggest-adding-bound-to-opaque-type.stderr
tests/ui/regions/higher-ranked-implied.rs [new file with mode: 0644]
tests/ui/regions/higher-ranked-implied.stderr [new file with mode: 0644]
tests/ui/regions/regions-addr-of-arg.stderr
tests/ui/regions/regions-free-region-ordering-caller1.stderr
tests/ui/regions/regions-infer-proc-static-upvar.stderr
tests/ui/regions/regions-nested-fns.stderr
tests/ui/regions/regions-pattern-typing-issue-19552.stderr
tests/ui/regions/regions-pattern-typing-issue-19997.stderr
tests/ui/reify-intrinsic.stderr
tests/ui/rfc-2008-non-exhaustive/borrowck-non-exhaustive.stderr
tests/ui/rfc-2497-if-let-chains/ensure-that-let-else-does-not-interact-with-let-chains.stderr
tests/ui/rfcs/rfc-2396-target_feature-11/fn-ptr.mir.stderr
tests/ui/rfcs/rfc-2396-target_feature-11/fn-ptr.thir.stderr
tests/ui/rfcs/rfc-2528-type-changing-struct-update/lifetime-update.stderr
tests/ui/self/arbitrary_self_types_pointers_and_wrappers.rs
tests/ui/self/issue-61882-2.stderr
tests/ui/span/borrowck-call-is-borrow-issue-12224.stderr
tests/ui/span/borrowck-let-suggestion-suffixes.rs
tests/ui/span/borrowck-let-suggestion-suffixes.stderr
tests/ui/span/destructor-restrictions.stderr
tests/ui/span/dropck-object-cycle.stderr
tests/ui/span/dropck_arr_cycle_checked.stderr
tests/ui/span/dropck_direct_cycle_with_drop.stderr
tests/ui/span/dropck_misc_variants.stderr
tests/ui/span/dropck_vec_cycle_checked.stderr
tests/ui/span/issue-23338-locals-die-before-temps-of-body.stderr
tests/ui/span/issue-24805-dropck-child-has-items-via-parent.stderr
tests/ui/span/issue-24805-dropck-trait-has-items.stderr
tests/ui/span/issue-24895-copy-clone-dropck.stderr
tests/ui/span/issue-25199.stderr
tests/ui/span/issue-26656.stderr
tests/ui/span/issue-29106.stderr
tests/ui/span/issue-36537.stderr
tests/ui/span/issue-40157.stderr
tests/ui/span/issue28498-reject-lifetime-param.stderr
tests/ui/span/issue28498-reject-passed-to-fn.stderr
tests/ui/span/issue28498-reject-trait-bound.stderr
tests/ui/span/mut-ptr-cant-outlive-ref.stderr
tests/ui/span/range-2.stderr
tests/ui/span/regionck-unboxed-closure-lifetimes.stderr
tests/ui/span/regions-close-over-type-parameter-2.stderr
tests/ui/span/regions-escape-loop-via-variable.stderr
tests/ui/span/regions-escape-loop-via-vec.stderr
tests/ui/span/regions-infer-borrow-scope-within-loop.stderr
tests/ui/span/send-is-not-static-ensures-scoping.stderr
tests/ui/span/send-is-not-static-std-sync-2.stderr
tests/ui/span/send-is-not-static-std-sync.stderr
tests/ui/span/vec-must-not-hide-type-from-dropck.stderr
tests/ui/span/vec_refs_data_with_early_death.stderr
tests/ui/span/wf-method-late-bound-regions.stderr
tests/ui/static/static-lifetime-bound.stderr
tests/ui/static/static-reference-to-fn-1.stderr
tests/ui/stdlib-unit-tests/not-sync.stderr
tests/ui/suggestions/assoc-const-without-self.rs [new file with mode: 0644]
tests/ui/suggestions/assoc-const-without-self.stderr [new file with mode: 0644]
tests/ui/suggestions/borrow-for-loop-head.stderr
tests/ui/suggestions/option-content-move2.stderr
tests/ui/suggestions/ref-pattern-binding.stderr
tests/ui/sync/mutexguard-sync.rs [new file with mode: 0644]
tests/ui/sync/mutexguard-sync.stderr [new file with mode: 0644]
tests/ui/sync/suggest-cell.rs [new file with mode: 0644]
tests/ui/sync/suggest-cell.stderr [new file with mode: 0644]
tests/ui/sync/suggest-once-cell.rs [new file with mode: 0644]
tests/ui/sync/suggest-once-cell.stderr [new file with mode: 0644]
tests/ui/sync/suggest-ref-cell.rs [new file with mode: 0644]
tests/ui/sync/suggest-ref-cell.stderr [new file with mode: 0644]
tests/ui/traits/associated_type_bound/check-trait-object-bounds-3.stderr
tests/ui/traits/coercion-generic-regions.stderr
tests/ui/traits/new-solver/async.fail.stderr [new file with mode: 0644]
tests/ui/traits/new-solver/async.rs [new file with mode: 0644]
tests/ui/traits/new-solver/generator.fail.stderr [new file with mode: 0644]
tests/ui/traits/new-solver/generator.rs [new file with mode: 0644]
tests/ui/traits/new-solver/pointee.rs [new file with mode: 0644]
tests/ui/traits/vtable/issue-97381.stderr
tests/ui/try-block/try-block-bad-lifetime.stderr
tests/ui/try-block/try-block-maybe-bad-lifetime.stderr
tests/ui/type-alias-impl-trait/bounds-are-checked.rs
tests/ui/type-alias-impl-trait/bounds-are-checked.stderr
tests/ui/type-alias-impl-trait/generic_nondefining_use.rs
tests/ui/type-alias-impl-trait/generic_nondefining_use.stderr
tests/ui/type/type-check/coerce-result-return-value-2.rs [new file with mode: 0644]
tests/ui/type/type-check/coerce-result-return-value-2.stderr [new file with mode: 0644]
tests/ui/type/type-check/coerce-result-return-value.fixed [new file with mode: 0644]
tests/ui/type/type-check/coerce-result-return-value.rs [new file with mode: 0644]
tests/ui/type/type-check/coerce-result-return-value.stderr [new file with mode: 0644]
tests/ui/typeck/bad-type-in-vec-push.rs [new file with mode: 0644]
tests/ui/typeck/bad-type-in-vec-push.stderr [new file with mode: 0644]
tests/ui/unboxed-closures/unboxed-closures-borrow-conflict.stderr
tests/ui/unboxed-closures/unboxed-closures-failed-recursive-fn-1.stderr
tests/ui/unop-move-semantics.stderr
tests/ui/variance/variance-issue-20533.stderr
triagebot.toml

index 8e1a3c57f0314e4e94756c50091ee73cec8147e2..23b01f23c50ead984a31f4d34034968bdbfa29d2 100644 (file)
@@ -351,7 +351,7 @@ dependencies = [
  "cargo-test-macro",
  "cargo-test-support",
  "cargo-util",
- "clap 4.1.1",
+ "clap 4.1.4",
  "crates-io",
  "curl",
  "curl-sys",
@@ -655,9 +655,9 @@ dependencies = [
 
 [[package]]
 name = "clap"
-version = "4.1.1"
+version = "4.1.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4ec7a4128863c188deefe750ac1d1dfe66c236909f845af04beed823638dc1b2"
+checksum = "f13b9c79b5d1dd500d20ef541215a6423c75829ef43117e1b4d17fd8af0b5d76"
 dependencies = [
  "bitflags",
  "clap_derive 4.1.0",
@@ -675,7 +675,7 @@ version = "4.0.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "10861370d2ba66b0f5989f83ebf35db6421713fd92351790e7fdd6c36774c56b"
 dependencies = [
- "clap 4.1.1",
+ "clap 4.1.4",
 ]
 
 [[package]]
@@ -1799,9 +1799,9 @@ dependencies = [
 
 [[package]]
 name = "git2"
-version = "0.16.1"
+version = "0.16.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ccf7f68c2995f392c49fffb4f95ae2c873297830eb25c6bc4c114ce8f4562acc"
+checksum = "be36bc9e0546df253c0cc41fd0af34f5e92845ad8509462ec76672fac6997f5b"
 dependencies = [
  "bitflags",
  "libc",
@@ -2294,7 +2294,7 @@ name = "jsondoclint"
 version = "0.1.0"
 dependencies = [
  "anyhow",
- "clap 4.1.1",
+ "clap 4.1.4",
  "fs-err",
  "rustdoc-json-types",
  "serde",
@@ -2365,9 +2365,9 @@ dependencies = [
 
 [[package]]
 name = "libgit2-sys"
-version = "0.14.2+1.5.1"
+version = "0.14.1+1.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7f3d95f6b51075fe9810a7ae22c7095f12b98005ab364d8544797a825ce946a4"
+checksum = "4a07fb2692bc3593bda59de45a502bb3071659f2c515e28c71e728306b038e17"
 dependencies = [
  "cc",
  "libc",
@@ -2557,7 +2557,7 @@ dependencies = [
  "ammonia",
  "anyhow",
  "chrono",
- "clap 4.1.1",
+ "clap 4.1.4",
  "clap_complete",
  "elasticlunr-rs",
  "env_logger 0.10.0",
@@ -3528,7 +3528,7 @@ dependencies = [
 name = "rustbook"
 version = "0.1.0"
 dependencies = [
- "clap 4.1.1",
+ "clap 4.1.4",
  "env_logger 0.7.1",
  "mdbook",
 ]
@@ -3729,6 +3729,7 @@ name = "rustc_ast_pretty"
 version = "0.0.0"
 dependencies = [
  "rustc_ast",
+ "rustc_parse_format",
  "rustc_span",
 ]
 
@@ -4926,7 +4927,7 @@ dependencies = [
 
 [[package]]
 name = "rustfmt-config_proc_macro"
-version = "0.2.0"
+version = "0.3.0"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -4936,7 +4937,7 @@ dependencies = [
 
 [[package]]
 name = "rustfmt-nightly"
-version = "1.5.1"
+version = "1.5.2"
 dependencies = [
  "annotate-snippets",
  "anyhow",
index 2901bfcc3e3e9f3612e6ebd48375bd8ca4707744..a63d4e8a043c606e4384eb5b7f6d6bc581802de9 100644 (file)
@@ -1,3 +1,106 @@
+Version 1.67.0 (2023-01-26)
+==========================
+
+<a id="1.67.0-Language"></a>
+
+Language
+--------
+
+- [Make `Sized` predicates coinductive, allowing cycles.](https://github.com/rust-lang/rust/pull/100386/)
+- [`#[must_use]` annotations on `async fn` also affect the `Future::Output`.](https://github.com/rust-lang/rust/pull/100633/)
+- [Elaborate supertrait obligations when deducing closure signatures.](https://github.com/rust-lang/rust/pull/101834/)
+- [Invalid literals are no longer an error under `cfg(FALSE)`.](https://github.com/rust-lang/rust/pull/102944/)
+- [Unreserve braced enum variants in value namespace.](https://github.com/rust-lang/rust/pull/103578/)
+
+<a id="1.67.0-Compiler"></a>
+
+Compiler
+--------
+
+- [Enable varargs support for calling conventions other than `C` or `cdecl`.](https://github.com/rust-lang/rust/pull/97971/)
+- [Add new MIR constant propagation based on dataflow analysis.](https://github.com/rust-lang/rust/pull/101168/)
+- [Optimize field ordering by grouping m\*2^n-sized fields with equivalently aligned ones.](https://github.com/rust-lang/rust/pull/102750/)
+- [Stabilize native library modifier `verbatim`.](https://github.com/rust-lang/rust/pull/104360/)
+
+Added and removed targets:
+
+- [Add a tier 3 target for PowerPC on AIX](https://github.com/rust-lang/rust/pull/102293/), `powerpc64-ibm-aix`.
+- [Add a tier 3 target for the Sony PlayStation 1](https://github.com/rust-lang/rust/pull/102689/), `mipsel-sony-psx`.
+- [Add tier 3 `no_std` targets for the QNX Neutrino RTOS](https://github.com/rust-lang/rust/pull/102701/),
+  `aarch64-unknown-nto-qnx710` and `x86_64-pc-nto-qnx710`.
+- [Remove tier 3 `linuxkernel` targets](https://github.com/rust-lang/rust/pull/104015/) (not used by the actual kernel).
+
+Refer to Rust's [platform support page][platform-support-doc]
+for more information on Rust's tiered platform support.
+
+<a id="1.67.0-Libraries"></a>
+
+Libraries
+---------
+
+- [Merge `crossbeam-channel` into `std::sync::mpsc`.](https://github.com/rust-lang/rust/pull/93563/)
+- [Fix inconsistent rounding of 0.5 when formatted to 0 decimal places.](https://github.com/rust-lang/rust/pull/102935/)
+- [Derive `Eq` and `Hash` for `ControlFlow`.](https://github.com/rust-lang/rust/pull/103084/)
+- [Don't build `compiler_builtins` with `-C panic=abort`.](https://github.com/rust-lang/rust/pull/103786/)
+
+<a id="1.67.0-Stabilized-APIs"></a>
+
+Stabilized APIs
+---------------
+
+- [`{integer}::checked_ilog`](https://doc.rust-lang.org/stable/std/primitive.i32.html#method.checked_ilog)
+- [`{integer}::checked_ilog2`](https://doc.rust-lang.org/stable/std/primitive.i32.html#method.checked_ilog2)
+- [`{integer}::checked_ilog10`](https://doc.rust-lang.org/stable/std/primitive.i32.html#method.checked_ilog10)
+- [`{integer}::ilog`](https://doc.rust-lang.org/stable/std/primitive.i32.html#method.ilog)
+- [`{integer}::ilog2`](https://doc.rust-lang.org/stable/std/primitive.i32.html#method.ilog2)
+- [`{integer}::ilog10`](https://doc.rust-lang.org/stable/std/primitive.i32.html#method.ilog10)
+- [`NonZeroU*::ilog2`](https://doc.rust-lang.org/stable/std/num/struct.NonZeroU32.html#method.ilog2)
+- [`NonZeroU*::ilog10`](https://doc.rust-lang.org/stable/std/num/struct.NonZeroU32.html#method.ilog10)
+- [`NonZero*::BITS`](https://doc.rust-lang.org/stable/std/num/struct.NonZeroU32.html#associatedconstant.BITS)
+
+These APIs are now stable in const contexts:
+
+- [`char::from_u32`](https://doc.rust-lang.org/stable/std/primitive.char.html#method.from_u32)
+- [`char::from_digit`](https://doc.rust-lang.org/stable/std/primitive.char.html#method.from_digit)
+- [`char::to_digit`](https://doc.rust-lang.org/stable/std/primitive.char.html#method.to_digit)
+- [`core::char::from_u32`](https://doc.rust-lang.org/stable/core/char/fn.from_u32.html)
+- [`core::char::from_digit`](https://doc.rust-lang.org/stable/core/char/fn.from_digit.html)
+
+<a id="1.67.0-Compatibility-Notes"></a>
+
+Compatibility Notes
+-------------------
+
+- [The layout of `repr(Rust)` types now groups m\*2^n-sized fields with
+  equivalently aligned ones.](https://github.com/rust-lang/rust/pull/102750/)
+  This is intended to be an optimization, but it is also known to increase type
+  sizes in a few cases for the placement of enum tags. As a reminder, the layout
+  of `repr(Rust)` types is an implementation detail, subject to change.
+- [0.5 now rounds to 0 when formatted to 0 decimal places.](https://github.com/rust-lang/rust/pull/102935/)
+  This makes it consistent with the rest of floating point formatting that
+  rounds ties toward even digits.
+- [Chains of `&&` and `||` will now drop temporaries from their sub-expressions in
+  evaluation order, left-to-right.](https://github.com/rust-lang/rust/pull/103293/)
+  Previously, it was "twisted" such that the _first_ expression dropped its
+  temporaries _last_, after all of the other expressions dropped in order.
+- [Underscore suffixes on string literals are now a hard error.](https://github.com/rust-lang/rust/pull/103914/)
+  This has been a future-compatibility warning since 1.20.0.
+- [Stop passing `-export-dynamic` to `wasm-ld`.](https://github.com/rust-lang/rust/pull/105405/)
+- [`main` is now mangled as `__main_void` on `wasm32-wasi`.](https://github.com/rust-lang/rust/pull/105468/)
+- [Cargo now emits an error if there are multiple registries in the configuration
+  with the same index URL.](https://github.com/rust-lang/cargo/pull/10592)
+
+<a id="1.67.0-Internal-Changes"></a>
+
+Internal Changes
+----------------
+
+These changes do not affect any public interfaces of Rust, but they represent
+significant improvements to the performance or internals of rustc and related
+tools.
+
+- [Rewrite LLVM's archive writer in Rust.](https://github.com/rust-lang/rust/pull/97485/)
+
 Version 1.66.1 (2023-01-10)
 ===========================
 
index f4cb459f32fddee1bcc78c465ae6916b8a92736e..fe65ad9c6cb0e9bde1aaff6e4801ef2f2b8c964a 100644 (file)
@@ -267,6 +267,9 @@ pub fn parse_from_llvm_datalayout_string<'a>(
                 ["a", ref a @ ..] => dl.aggregate_align = align(a, "a")?,
                 ["f32", ref a @ ..] => dl.f32_align = align(a, "f32")?,
                 ["f64", ref a @ ..] => dl.f64_align = align(a, "f64")?,
+                // FIXME(erikdesjardins): we should be parsing nonzero address spaces
+                // this will require replacing TargetDataLayout::{pointer_size,pointer_align}
+                // with e.g. `fn pointer_size_in(AddressSpace)`
                 [p @ "p", s, ref a @ ..] | [p @ "p0", s, ref a @ ..] => {
                     dl.pointer_size = size(s, p)?;
                     dl.pointer_align = align(a, p)?;
@@ -861,7 +864,7 @@ pub enum Primitive {
     Int(Integer, bool),
     F32,
     F64,
-    Pointer,
+    Pointer(AddressSpace),
 }
 
 impl Primitive {
@@ -872,7 +875,10 @@ pub fn size<C: HasDataLayout>(self, cx: &C) -> Size {
             Int(i, _) => i.size(),
             F32 => Size::from_bits(32),
             F64 => Size::from_bits(64),
-            Pointer => dl.pointer_size,
+            // FIXME(erikdesjardins): ignoring address space is technically wrong, pointers in
+            // different address spaces can have different sizes
+            // (but TargetDataLayout doesn't currently parse that part of the DL string)
+            Pointer(_) => dl.pointer_size,
         }
     }
 
@@ -883,26 +889,12 @@ pub fn align<C: HasDataLayout>(self, cx: &C) -> AbiAndPrefAlign {
             Int(i, _) => i.align(dl),
             F32 => dl.f32_align,
             F64 => dl.f64_align,
-            Pointer => dl.pointer_align,
+            // FIXME(erikdesjardins): ignoring address space is technically wrong, pointers in
+            // different address spaces can have different alignments
+            // (but TargetDataLayout doesn't currently parse that part of the DL string)
+            Pointer(_) => dl.pointer_align,
         }
     }
-
-    // FIXME(eddyb) remove, it's trivial thanks to `matches!`.
-    #[inline]
-    pub fn is_float(self) -> bool {
-        matches!(self, F32 | F64)
-    }
-
-    // FIXME(eddyb) remove, it's completely unused.
-    #[inline]
-    pub fn is_int(self) -> bool {
-        matches!(self, Int(..))
-    }
-
-    #[inline]
-    pub fn is_ptr(self) -> bool {
-        matches!(self, Pointer)
-    }
 }
 
 /// Inclusive wrap-around range of valid values, that is, if
@@ -1188,7 +1180,8 @@ pub fn index_by_increasing_offset<'a>(&'a self) -> impl Iterator<Item = usize> +
 /// An identifier that specifies the address space that some operation
 /// should operate on. Special address spaces have an effect on code generation,
 /// depending on the target and the address spaces it implements.
-#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
+#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
+#[cfg_attr(feature = "nightly", derive(HashStable_Generic))]
 pub struct AddressSpace(pub u32);
 
 impl AddressSpace {
@@ -1468,7 +1461,6 @@ pub struct PointeeInfo {
     pub size: Size,
     pub align: Align,
     pub safe: Option<PointerKind>,
-    pub address_space: AddressSpace,
 }
 
 /// Used in `might_permit_raw_init` to indicate the kind of initialisation
index 9317579f70dd5967cb5e80382c8cab541c58ecea..8ad3270c5103ec24cbd11429b4f7cd7984fba6fd 100644 (file)
@@ -18,6 +18,7 @@
 //! - [`Attribute`]: Metadata associated with item.
 //! - [`UnOp`], [`BinOp`], and [`BinOpKind`]: Unary and binary operators.
 
+pub use crate::format::*;
 pub use crate::util::parser::ExprPrecedence;
 pub use GenericArgs::*;
 pub use UnsafeSource::*;
@@ -1269,6 +1270,7 @@ pub fn precedence(&self) -> ExprPrecedence {
             ExprKind::Try(..) => ExprPrecedence::Try,
             ExprKind::Yield(..) => ExprPrecedence::Yield,
             ExprKind::Yeet(..) => ExprPrecedence::Yeet,
+            ExprKind::FormatArgs(..) => ExprPrecedence::FormatArgs,
             ExprKind::Err => ExprPrecedence::Err,
         }
     }
@@ -1499,6 +1501,9 @@ pub enum ExprKind {
     /// with a `ByteStr` literal.
     IncludedBytes(Lrc<[u8]>),
 
+    /// A `format_args!()` expression.
+    FormatArgs(P<FormatArgs>),
+
     /// Placeholder for an expression that wasn't syntactically well formed in some way.
     Err,
 }
diff --git a/compiler/rustc_ast/src/format.rs b/compiler/rustc_ast/src/format.rs
new file mode 100644 (file)
index 0000000..da05b09
--- /dev/null
@@ -0,0 +1,250 @@
+use crate::ptr::P;
+use crate::Expr;
+use rustc_data_structures::fx::FxHashMap;
+use rustc_span::symbol::{Ident, Symbol};
+use rustc_span::Span;
+
+// Definitions:
+//
+// format_args!("hello {abc:.xyz$}!!", abc="world");
+// └──────────────────────────────────────────────┘
+//                     FormatArgs
+//
+// format_args!("hello {abc:.xyz$}!!", abc="world");
+//                                     └─────────┘
+//                                      argument
+//
+// format_args!("hello {abc:.xyz$}!!", abc="world");
+//              └───────────────────┘
+//                     template
+//
+// format_args!("hello {abc:.xyz$}!!", abc="world");
+//               └────┘└─────────┘└┘
+//                      pieces
+//
+// format_args!("hello {abc:.xyz$}!!", abc="world");
+//               └────┘           └┘
+//                   literal pieces
+//
+// format_args!("hello {abc:.xyz$}!!", abc="world");
+//                     └─────────┘
+//                     placeholder
+//
+// format_args!("hello {abc:.xyz$}!!", abc="world");
+//                      └─┘  └─┘
+//                      positions (could be names, numbers, empty, or `*`)
+
+/// (Parsed) format args.
+///
+/// Basically the "AST" for a complete `format_args!()`.
+///
+/// E.g., `format_args!("hello {name}");`.
+#[derive(Clone, Encodable, Decodable, Debug)]
+pub struct FormatArgs {
+    pub span: Span,
+    pub template: Vec<FormatArgsPiece>,
+    pub arguments: FormatArguments,
+}
+
+/// A piece of a format template string.
+///
+/// E.g. "hello" or "{name}".
+#[derive(Clone, Encodable, Decodable, Debug)]
+pub enum FormatArgsPiece {
+    Literal(Symbol),
+    Placeholder(FormatPlaceholder),
+}
+
+/// The arguments to format_args!().
+///
+/// E.g. `1, 2, name="ferris", n=3`,
+/// but also implicit captured arguments like `x` in `format_args!("{x}")`.
+#[derive(Clone, Encodable, Decodable, Debug)]
+pub struct FormatArguments {
+    arguments: Vec<FormatArgument>,
+    num_unnamed_args: usize,
+    num_explicit_args: usize,
+    names: FxHashMap<Symbol, usize>,
+}
+
+// FIXME: Rustdoc has trouble proving Send/Sync for this. See #106930.
+#[cfg(parallel_compiler)]
+unsafe impl Sync for FormatArguments {}
+#[cfg(parallel_compiler)]
+unsafe impl Send for FormatArguments {}
+
+impl FormatArguments {
+    pub fn new() -> Self {
+        Self {
+            arguments: Vec::new(),
+            names: FxHashMap::default(),
+            num_unnamed_args: 0,
+            num_explicit_args: 0,
+        }
+    }
+
+    pub fn add(&mut self, arg: FormatArgument) -> usize {
+        let index = self.arguments.len();
+        if let Some(name) = arg.kind.ident() {
+            self.names.insert(name.name, index);
+        } else if self.names.is_empty() {
+            // Only count the unnamed args before the first named arg.
+            // (Any later ones are errors.)
+            self.num_unnamed_args += 1;
+        }
+        if !matches!(arg.kind, FormatArgumentKind::Captured(..)) {
+            // This is an explicit argument.
+            // Make sure that all arguments so far are explcit.
+            assert_eq!(
+                self.num_explicit_args,
+                self.arguments.len(),
+                "captured arguments must be added last"
+            );
+            self.num_explicit_args += 1;
+        }
+        self.arguments.push(arg);
+        index
+    }
+
+    pub fn by_name(&self, name: Symbol) -> Option<(usize, &FormatArgument)> {
+        let i = *self.names.get(&name)?;
+        Some((i, &self.arguments[i]))
+    }
+
+    pub fn by_index(&self, i: usize) -> Option<&FormatArgument> {
+        (i < self.num_explicit_args).then(|| &self.arguments[i])
+    }
+
+    pub fn unnamed_args(&self) -> &[FormatArgument] {
+        &self.arguments[..self.num_unnamed_args]
+    }
+
+    pub fn named_args(&self) -> &[FormatArgument] {
+        &self.arguments[self.num_unnamed_args..self.num_explicit_args]
+    }
+
+    pub fn explicit_args(&self) -> &[FormatArgument] {
+        &self.arguments[..self.num_explicit_args]
+    }
+
+    pub fn all_args(&self) -> &[FormatArgument] {
+        &self.arguments[..]
+    }
+
+    pub fn all_args_mut(&mut self) -> &mut [FormatArgument] {
+        &mut self.arguments[..]
+    }
+}
+
+#[derive(Clone, Encodable, Decodable, Debug)]
+pub struct FormatArgument {
+    pub kind: FormatArgumentKind,
+    pub expr: P<Expr>,
+}
+
+#[derive(Clone, Encodable, Decodable, Debug)]
+pub enum FormatArgumentKind {
+    /// `format_args(…, arg)`
+    Normal,
+    /// `format_args(…, arg = 1)`
+    Named(Ident),
+    /// `format_args("… {arg} …")`
+    Captured(Ident),
+}
+
+impl FormatArgumentKind {
+    pub fn ident(&self) -> Option<Ident> {
+        match self {
+            &Self::Normal => None,
+            &Self::Named(id) => Some(id),
+            &Self::Captured(id) => Some(id),
+        }
+    }
+}
+
+#[derive(Clone, Encodable, Decodable, Debug, PartialEq, Eq)]
+pub struct FormatPlaceholder {
+    /// Index into [`FormatArgs::arguments`].
+    pub argument: FormatArgPosition,
+    /// The span inside the format string for the full `{…}` placeholder.
+    pub span: Option<Span>,
+    /// `{}`, `{:?}`, or `{:x}`, etc.
+    pub format_trait: FormatTrait,
+    /// `{}` or `{:.5}` or `{:-^20}`, etc.
+    pub format_options: FormatOptions,
+}
+
+#[derive(Clone, Encodable, Decodable, Debug, PartialEq, Eq)]
+pub struct FormatArgPosition {
+    /// Which argument this position refers to (Ok),
+    /// or would've referred to if it existed (Err).
+    pub index: Result<usize, usize>,
+    /// What kind of position this is. See [`FormatArgPositionKind`].
+    pub kind: FormatArgPositionKind,
+    /// The span of the name or number.
+    pub span: Option<Span>,
+}
+
+#[derive(Copy, Clone, Encodable, Decodable, Debug, PartialEq, Eq)]
+pub enum FormatArgPositionKind {
+    /// `{}` or `{:.*}`
+    Implicit,
+    /// `{1}` or `{:1$}` or `{:.1$}`
+    Number,
+    /// `{a}` or `{:a$}` or `{:.a$}`
+    Named,
+}
+
+#[derive(Copy, Clone, Encodable, Decodable, Debug, PartialEq, Eq, Hash)]
+pub enum FormatTrait {
+    /// `{}`
+    Display,
+    /// `{:?}`
+    Debug,
+    /// `{:e}`
+    LowerExp,
+    /// `{:E}`
+    UpperExp,
+    /// `{:o}`
+    Octal,
+    /// `{:p}`
+    Pointer,
+    /// `{:b}`
+    Binary,
+    /// `{:x}`
+    LowerHex,
+    /// `{:X}`
+    UpperHex,
+}
+
+#[derive(Clone, Encodable, Decodable, Default, Debug, PartialEq, Eq)]
+pub struct FormatOptions {
+    /// The width. E.g. `{:5}` or `{:width$}`.
+    pub width: Option<FormatCount>,
+    /// The precision. E.g. `{:.5}` or `{:.precision$}`.
+    pub precision: Option<FormatCount>,
+    /// The alignment. E.g. `{:>}` or `{:<}` or `{:^}`.
+    pub alignment: Option<FormatAlignment>,
+    /// The fill character. E.g. the `.` in `{:.>10}`.
+    pub fill: Option<char>,
+    /// The `+`, `-`, `0`, `#`, `x?` and `X?` flags.
+    pub flags: u32,
+}
+
+#[derive(Copy, Clone, Encodable, Decodable, Debug, PartialEq, Eq)]
+pub enum FormatAlignment {
+    /// `{:<}`
+    Left,
+    /// `{:>}`
+    Right,
+    /// `{:^}`
+    Center,
+}
+
+#[derive(Clone, Encodable, Decodable, Debug, PartialEq, Eq)]
+pub enum FormatCount {
+    /// `{:5}` or `{:.5}`
+    Literal(usize),
+    /// `{:.*}`, `{:.5$}`, or `{:a$}`, etc.
+    Argument(FormatArgPosition),
+}
index 9c1dfeb1a61428920e20e4ac69f61e9913701094..0f8ebcfdc150844ad4d72751ac8619161bfbbed0 100644 (file)
@@ -42,6 +42,7 @@ pub mod util {
 pub mod attr;
 pub mod entry;
 pub mod expand;
+pub mod format;
 pub mod mut_visit;
 pub mod node_id;
 pub mod ptr;
@@ -51,6 +52,7 @@ pub mod util {
 
 pub use self::ast::*;
 pub use self::ast_traits::{AstDeref, AstNodeWrapper, HasAttrs, HasNodeId, HasSpan, HasTokens};
+pub use self::format::*;
 
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 
index 77f342d1eb322efe2a35deb211006e6408a243b5..1dd62626b8f5e33607a4e87a362b4875997128ef 100644 (file)
@@ -297,6 +297,10 @@ fn visit_inline_asm(&mut self, asm: &mut InlineAsm) {
     fn visit_inline_asm_sym(&mut self, sym: &mut InlineAsmSym) {
         noop_visit_inline_asm_sym(sym, self)
     }
+
+    fn visit_format_args(&mut self, fmt: &mut FormatArgs) {
+        noop_visit_format_args(fmt, self)
+    }
 }
 
 /// Use a map-style function (`FnOnce(T) -> T`) to overwrite a `&mut T`. Useful
@@ -1284,6 +1288,15 @@ pub fn noop_visit_inline_asm_sym<T: MutVisitor>(
     vis.visit_path(path);
 }
 
+pub fn noop_visit_format_args<T: MutVisitor>(fmt: &mut FormatArgs, vis: &mut T) {
+    for arg in fmt.arguments.all_args_mut() {
+        if let FormatArgumentKind::Named(name) = &mut arg.kind {
+            vis.visit_ident(name);
+        }
+        vis.visit_expr(&mut arg.expr);
+    }
+}
+
 pub fn noop_visit_expr<T: MutVisitor>(
     Expr { kind, id, span, attrs, tokens }: &mut Expr,
     vis: &mut T,
@@ -1425,6 +1438,7 @@ pub fn noop_visit_expr<T: MutVisitor>(
             visit_opt(expr, |expr| vis.visit_expr(expr));
         }
         ExprKind::InlineAsm(asm) => vis.visit_inline_asm(asm),
+        ExprKind::FormatArgs(fmt) => vis.visit_format_args(fmt),
         ExprKind::MacCall(mac) => vis.visit_mac_call(mac),
         ExprKind::Struct(se) => {
             let StructExpr { qself, path, fields, rest } = se.deref_mut();
index 4f7099c7be8a6561492a22b210643768b9db4a2a..81efdaa44b365a3979187d37a540640636784a4f 100644 (file)
@@ -271,6 +271,7 @@ pub enum ExprPrecedence {
     Try,
     InlineAsm,
     Mac,
+    FormatArgs,
 
     Array,
     Repeat,
@@ -335,7 +336,8 @@ pub fn order(self) -> i8 {
             | ExprPrecedence::Index
             | ExprPrecedence::Try
             | ExprPrecedence::InlineAsm
-            | ExprPrecedence::Mac => PREC_POSTFIX,
+            | ExprPrecedence::Mac
+            | ExprPrecedence::FormatArgs => PREC_POSTFIX,
 
             // Never need parens
             ExprPrecedence::Array
index e8823eff83afe1bab63061dd862a7ed40af53575..e7b2e4b1cb4b072a4d300e0e20b978fa16fb2ee4 100644 (file)
@@ -242,6 +242,9 @@ fn visit_crate(&mut self, krate: &'ast Crate) {
     fn visit_inline_asm(&mut self, asm: &'ast InlineAsm) {
         walk_inline_asm(self, asm)
     }
+    fn visit_format_args(&mut self, fmt: &'ast FormatArgs) {
+        walk_format_args(self, fmt)
+    }
     fn visit_inline_asm_sym(&mut self, sym: &'ast InlineAsmSym) {
         walk_inline_asm_sym(self, sym)
     }
@@ -400,8 +403,8 @@ pub fn walk_ty<'a, V: Visitor<'a>>(visitor: &mut V, typ: &'a Ty) {
             walk_list!(visitor, visit_lifetime, opt_lifetime, LifetimeCtxt::Ref);
             visitor.visit_ty(&mutable_type.ty)
         }
-        TyKind::Tup(tuple_element_types) => {
-            walk_list!(visitor, visit_ty, tuple_element_types);
+        TyKind::Tup(tys) => {
+            walk_list!(visitor, visit_ty, tys);
         }
         TyKind::BareFn(function_declaration) => {
             walk_list!(visitor, visit_generic_param, &function_declaration.generic_params);
@@ -756,6 +759,15 @@ pub fn walk_inline_asm_sym<'a, V: Visitor<'a>>(visitor: &mut V, sym: &'a InlineA
     visitor.visit_path(&sym.path, sym.id);
 }
 
+pub fn walk_format_args<'a, V: Visitor<'a>>(visitor: &mut V, fmt: &'a FormatArgs) {
+    for arg in fmt.arguments.all_args() {
+        if let FormatArgumentKind::Named(name) = arg.kind {
+            visitor.visit_ident(name);
+        }
+        visitor.visit_expr(&arg.expr);
+    }
+}
+
 pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) {
     walk_list!(visitor, visit_attribute, expression.attrs.iter());
 
@@ -896,6 +908,7 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) {
         ExprKind::MacCall(mac) => visitor.visit_mac_call(mac),
         ExprKind::Paren(subexpression) => visitor.visit_expr(subexpression),
         ExprKind::InlineAsm(asm) => visitor.visit_inline_asm(asm),
+        ExprKind::FormatArgs(f) => visitor.visit_format_args(f),
         ExprKind::Yield(optional_expression) => {
             walk_list!(visitor, visit_expr, optional_expression);
         }
index c3611b2f522babd789e589285b1e6359e1f11b18..cc523fe7d08f501b44b9c81e35d307ed179b0423 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::{sym, Ident, Symbol};
 use rustc_span::DUMMY_SP;
 use thin_vec::thin_vec;
 
@@ -294,6 +294,7 @@ pub(super) fn lower_expr_mut(&mut self, e: &Expr) -> hir::Expr<'hir> {
                 ExprKind::InlineAsm(asm) => {
                     hir::ExprKind::InlineAsm(self.lower_inline_asm(e.span, asm))
                 }
+                ExprKind::FormatArgs(fmt) => self.lower_format_args(e.span, fmt),
                 ExprKind::Struct(se) => {
                     let rest = match &se.rest {
                         StructRest::Base(e) => Some(self.lower_expr(e)),
@@ -1735,7 +1736,7 @@ pub(super) fn expr_drop_temps_mut(
         self.expr(span, hir::ExprKind::DropTemps(expr))
     }
 
-    fn expr_match(
+    pub(super) fn expr_match(
         &mut self,
         span: Span,
         arg: &'hir hir::Expr<'hir>,
@@ -1763,7 +1764,44 @@ fn expr_unit(&mut self, sp: Span) -> &'hir hir::Expr<'hir> {
         self.arena.alloc(self.expr(sp, hir::ExprKind::Tup(&[])))
     }
 
-    fn expr_call_mut(
+    pub(super) fn expr_usize(&mut self, sp: Span, value: usize) -> hir::Expr<'hir> {
+        self.expr(
+            sp,
+            hir::ExprKind::Lit(hir::Lit {
+                span: sp,
+                node: ast::LitKind::Int(
+                    value as u128,
+                    ast::LitIntType::Unsigned(ast::UintTy::Usize),
+                ),
+            }),
+        )
+    }
+
+    pub(super) fn expr_u32(&mut self, sp: Span, value: u32) -> hir::Expr<'hir> {
+        self.expr(
+            sp,
+            hir::ExprKind::Lit(hir::Lit {
+                span: sp,
+                node: ast::LitKind::Int(value.into(), ast::LitIntType::Unsigned(ast::UintTy::U32)),
+            }),
+        )
+    }
+
+    pub(super) fn expr_char(&mut self, sp: Span, value: char) -> hir::Expr<'hir> {
+        self.expr(sp, hir::ExprKind::Lit(hir::Lit { span: sp, node: ast::LitKind::Char(value) }))
+    }
+
+    pub(super) fn expr_str(&mut self, sp: Span, value: Symbol) -> hir::Expr<'hir> {
+        self.expr(
+            sp,
+            hir::ExprKind::Lit(hir::Lit {
+                span: sp,
+                node: ast::LitKind::Str(value, ast::StrStyle::Cooked),
+            }),
+        )
+    }
+
+    pub(super) fn expr_call_mut(
         &mut self,
         span: Span,
         e: &'hir hir::Expr<'hir>,
@@ -1772,7 +1810,7 @@ fn expr_call_mut(
         self.expr(span, hir::ExprKind::Call(e, args))
     }
 
-    fn expr_call(
+    pub(super) fn expr_call(
         &mut self,
         span: Span,
         e: &'hir hir::Expr<'hir>,
@@ -1814,6 +1852,27 @@ fn expr_lang_item_path(
         )
     }
 
+    /// `<LangItem>::name`
+    pub(super) fn expr_lang_item_type_relative(
+        &mut self,
+        span: Span,
+        lang_item: hir::LangItem,
+        name: Symbol,
+    ) -> hir::Expr<'hir> {
+        let path = hir::ExprKind::Path(hir::QPath::TypeRelative(
+            self.arena.alloc(self.ty(
+                span,
+                hir::TyKind::Path(hir::QPath::LangItem(lang_item, self.lower_span(span), None)),
+            )),
+            self.arena.alloc(hir::PathSegment::new(
+                Ident::new(name, span),
+                self.next_id(),
+                Res::Err,
+            )),
+        ));
+        self.expr(span, path)
+    }
+
     pub(super) fn expr_ident(
         &mut self,
         sp: Span,
@@ -1872,12 +1931,25 @@ 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_array_ref(
+        &mut self,
+        span: Span,
+        elements: &'hir [hir::Expr<'hir>],
+    ) -> hir::Expr<'hir> {
+        let addrof = hir::ExprKind::AddrOf(
+            hir::BorrowKind::Ref,
+            hir::Mutability::Not,
+            self.arena.alloc(self.expr(span, hir::ExprKind::Array(elements))),
+        );
+        self.expr(span, addrof)
+    }
+
     pub(super) fn expr(&mut self, span: Span, kind: hir::ExprKind<'hir>) -> hir::Expr<'hir> {
         let hir_id = self.next_id();
         hir::Expr { hir_id, kind, span: self.lower_span(span) }
     }
 
-    fn expr_field(
+    pub(super) fn expr_field(
         &mut self,
         ident: Ident,
         expr: &'hir hir::Expr<'hir>,
@@ -1892,7 +1964,11 @@ fn expr_field(
         }
     }
 
-    fn arm(&mut self, pat: &'hir hir::Pat<'hir>, expr: &'hir hir::Expr<'hir>) -> hir::Arm<'hir> {
+    pub(super) fn arm(
+        &mut self,
+        pat: &'hir hir::Pat<'hir>,
+        expr: &'hir hir::Expr<'hir>,
+    ) -> hir::Arm<'hir> {
         hir::Arm {
             hir_id: self.next_id(),
             pat,
diff --git a/compiler/rustc_ast_lowering/src/format.rs b/compiler/rustc_ast_lowering/src/format.rs
new file mode 100644 (file)
index 0000000..776b532
--- /dev/null
@@ -0,0 +1,381 @@
+use super::LoweringContext;
+use rustc_ast as ast;
+use rustc_ast::visit::{self, Visitor};
+use rustc_ast::*;
+use rustc_data_structures::fx::FxIndexSet;
+use rustc_hir as hir;
+use rustc_span::{
+    sym,
+    symbol::{kw, Ident},
+    Span,
+};
+
+impl<'hir> LoweringContext<'_, 'hir> {
+    pub(crate) fn lower_format_args(&mut self, sp: Span, fmt: &FormatArgs) -> hir::ExprKind<'hir> {
+        expand_format_args(self, sp, fmt)
+    }
+}
+
+#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
+enum ArgumentType {
+    Format(FormatTrait),
+    Usize,
+}
+
+/// Generate a hir expression representing an argument to a format_args invocation.
+///
+/// Generates:
+///
+/// ```text
+///     <core::fmt::ArgumentV1>::new_…(arg)
+/// ```
+fn make_argument<'hir>(
+    ctx: &mut LoweringContext<'_, 'hir>,
+    sp: Span,
+    arg: &'hir hir::Expr<'hir>,
+    ty: ArgumentType,
+) -> hir::Expr<'hir> {
+    use ArgumentType::*;
+    use FormatTrait::*;
+    let new_fn = ctx.arena.alloc(ctx.expr_lang_item_type_relative(
+        sp,
+        hir::LangItem::FormatArgument,
+        match ty {
+            Format(Display) => sym::new_display,
+            Format(Debug) => sym::new_debug,
+            Format(LowerExp) => sym::new_lower_exp,
+            Format(UpperExp) => sym::new_upper_exp,
+            Format(Octal) => sym::new_octal,
+            Format(Pointer) => sym::new_pointer,
+            Format(Binary) => sym::new_binary,
+            Format(LowerHex) => sym::new_lower_hex,
+            Format(UpperHex) => sym::new_upper_hex,
+            Usize => sym::from_usize,
+        },
+    ));
+    ctx.expr_call_mut(sp, new_fn, std::slice::from_ref(arg))
+}
+
+/// Generate a hir expression for a format_args Count.
+///
+/// Generates:
+///
+/// ```text
+///     <core::fmt::rt::v1::Count>::Is(…)
+/// ```
+///
+/// or
+///
+/// ```text
+///     <core::fmt::rt::v1::Count>::Param(…)
+/// ```
+///
+/// or
+///
+/// ```text
+///     <core::fmt::rt::v1::Count>::Implied
+/// ```
+fn make_count<'hir>(
+    ctx: &mut LoweringContext<'_, 'hir>,
+    sp: Span,
+    count: &Option<FormatCount>,
+    argmap: &mut FxIndexSet<(usize, ArgumentType)>,
+) -> hir::Expr<'hir> {
+    match count {
+        Some(FormatCount::Literal(n)) => {
+            let count_is = ctx.arena.alloc(ctx.expr_lang_item_type_relative(
+                sp,
+                hir::LangItem::FormatCount,
+                sym::Is,
+            ));
+            let value = ctx.arena.alloc_from_iter([ctx.expr_usize(sp, *n)]);
+            ctx.expr_call_mut(sp, count_is, value)
+        }
+        Some(FormatCount::Argument(arg)) => {
+            if let Ok(arg_index) = arg.index {
+                let (i, _) = argmap.insert_full((arg_index, ArgumentType::Usize));
+                let count_param = ctx.arena.alloc(ctx.expr_lang_item_type_relative(
+                    sp,
+                    hir::LangItem::FormatCount,
+                    sym::Param,
+                ));
+                let value = ctx.arena.alloc_from_iter([ctx.expr_usize(sp, i)]);
+                ctx.expr_call_mut(sp, count_param, value)
+            } else {
+                ctx.expr(sp, hir::ExprKind::Err)
+            }
+        }
+        None => ctx.expr_lang_item_type_relative(sp, hir::LangItem::FormatCount, sym::Implied),
+    }
+}
+
+/// Generate a hir expression for a format_args placeholder specification.
+///
+/// Generates
+///
+/// ```text
+///     <core::fmt::rt::v1::Argument::new(
+///         …usize, // position
+///         '…', // fill
+///         <core::fmt::rt::v1::Alignment>::…, // alignment
+///         …u32, // flags
+///         <core::fmt::rt::v1::Count::…>, // width
+///         <core::fmt::rt::v1::Count::…>, // precision
+///     )
+/// ```
+fn make_format_spec<'hir>(
+    ctx: &mut LoweringContext<'_, 'hir>,
+    sp: Span,
+    placeholder: &FormatPlaceholder,
+    argmap: &mut FxIndexSet<(usize, ArgumentType)>,
+) -> hir::Expr<'hir> {
+    let position = match placeholder.argument.index {
+        Ok(arg_index) => {
+            let (i, _) =
+                argmap.insert_full((arg_index, ArgumentType::Format(placeholder.format_trait)));
+            ctx.expr_usize(sp, i)
+        }
+        Err(_) => ctx.expr(sp, hir::ExprKind::Err),
+    };
+    let fill = ctx.expr_char(sp, placeholder.format_options.fill.unwrap_or(' '));
+    let align = ctx.expr_lang_item_type_relative(
+        sp,
+        hir::LangItem::FormatAlignment,
+        match placeholder.format_options.alignment {
+            Some(FormatAlignment::Left) => sym::Left,
+            Some(FormatAlignment::Right) => sym::Right,
+            Some(FormatAlignment::Center) => sym::Center,
+            None => sym::Unknown,
+        },
+    );
+    let flags = ctx.expr_u32(sp, placeholder.format_options.flags);
+    let prec = make_count(ctx, sp, &placeholder.format_options.precision, argmap);
+    let width = make_count(ctx, sp, &placeholder.format_options.width, argmap);
+    let format_placeholder_new = ctx.arena.alloc(ctx.expr_lang_item_type_relative(
+        sp,
+        hir::LangItem::FormatPlaceholder,
+        sym::new,
+    ));
+    let args = ctx.arena.alloc_from_iter([position, fill, align, flags, prec, width]);
+    ctx.expr_call_mut(sp, format_placeholder_new, args)
+}
+
+fn expand_format_args<'hir>(
+    ctx: &mut LoweringContext<'_, 'hir>,
+    macsp: Span,
+    fmt: &FormatArgs,
+) -> hir::ExprKind<'hir> {
+    let lit_pieces =
+        ctx.arena.alloc_from_iter(fmt.template.iter().enumerate().filter_map(|(i, piece)| {
+            match piece {
+                &FormatArgsPiece::Literal(s) => Some(ctx.expr_str(fmt.span, s)),
+                &FormatArgsPiece::Placeholder(_) => {
+                    // Inject empty string before placeholders when not already preceded by a literal piece.
+                    if i == 0 || matches!(fmt.template[i - 1], FormatArgsPiece::Placeholder(_)) {
+                        Some(ctx.expr_str(fmt.span, kw::Empty))
+                    } else {
+                        None
+                    }
+                }
+            }
+        }));
+    let lit_pieces = ctx.expr_array_ref(fmt.span, lit_pieces);
+
+    // Whether we'll use the `Arguments::new_v1_formatted` form (true),
+    // or the `Arguments::new_v1` form (false).
+    let mut use_format_options = false;
+
+    // Create a list of all _unique_ (argument, format trait) combinations.
+    // E.g. "{0} {0:x} {0} {1}" -> [(0, Display), (0, LowerHex), (1, Display)]
+    let mut argmap = FxIndexSet::default();
+    for piece in &fmt.template {
+        let FormatArgsPiece::Placeholder(placeholder) = piece else { continue };
+        if placeholder.format_options != Default::default() {
+            // Can't use basic form if there's any formatting options.
+            use_format_options = true;
+        }
+        if let Ok(index) = placeholder.argument.index {
+            if !argmap.insert((index, ArgumentType::Format(placeholder.format_trait))) {
+                // Duplicate (argument, format trait) combination,
+                // which we'll only put once in the args array.
+                use_format_options = true;
+            }
+        }
+    }
+
+    let format_options = use_format_options.then(|| {
+        // Generate:
+        //     &[format_spec_0, format_spec_1, format_spec_2]
+        let elements: Vec<_> = fmt
+            .template
+            .iter()
+            .filter_map(|piece| {
+                let FormatArgsPiece::Placeholder(placeholder) = piece else { return None };
+                Some(make_format_spec(ctx, macsp, placeholder, &mut argmap))
+            })
+            .collect();
+        ctx.expr_array_ref(macsp, ctx.arena.alloc_from_iter(elements))
+    });
+
+    let arguments = fmt.arguments.all_args();
+
+    // If the args array contains exactly all the original arguments once,
+    // in order, we can use a simple array instead of a `match` construction.
+    // However, if there's a yield point in any argument except the first one,
+    // we don't do this, because an ArgumentV1 cannot be kept across yield points.
+    //
+    // This is an optimization, speeding up compilation about 1-2% in some cases.
+    // See https://github.com/rust-lang/rust/pull/106770#issuecomment-1380790609
+    let use_simple_array = argmap.len() == arguments.len()
+        && argmap.iter().enumerate().all(|(i, &(j, _))| i == j)
+        && arguments.iter().skip(1).all(|arg| !may_contain_yield_point(&arg.expr));
+
+    let args = if use_simple_array {
+        // Generate:
+        //     &[
+        //         <core::fmt::ArgumentV1>::new_display(&arg0),
+        //         <core::fmt::ArgumentV1>::new_lower_hex(&arg1),
+        //         <core::fmt::ArgumentV1>::new_debug(&arg2),
+        //         …
+        //     ]
+        let elements: Vec<_> = arguments
+            .iter()
+            .zip(argmap)
+            .map(|(arg, (_, ty))| {
+                let sp = arg.expr.span.with_ctxt(macsp.ctxt());
+                let arg = ctx.lower_expr(&arg.expr);
+                let ref_arg = ctx.arena.alloc(ctx.expr(
+                    sp,
+                    hir::ExprKind::AddrOf(hir::BorrowKind::Ref, hir::Mutability::Not, arg),
+                ));
+                make_argument(ctx, sp, ref_arg, ty)
+            })
+            .collect();
+        ctx.expr_array_ref(macsp, ctx.arena.alloc_from_iter(elements))
+    } else {
+        // Generate:
+        //     &match (&arg0, &arg1, &…) {
+        //         args => [
+        //             <core::fmt::ArgumentV1>::new_display(args.0),
+        //             <core::fmt::ArgumentV1>::new_lower_hex(args.1),
+        //             <core::fmt::ArgumentV1>::new_debug(args.0),
+        //             …
+        //         ]
+        //     }
+        let args_ident = Ident::new(sym::args, macsp);
+        let (args_pat, args_hir_id) = ctx.pat_ident(macsp, args_ident);
+        let args = ctx.arena.alloc_from_iter(argmap.iter().map(|&(arg_index, ty)| {
+            if let Some(arg) = arguments.get(arg_index) {
+                let sp = arg.expr.span.with_ctxt(macsp.ctxt());
+                let args_ident_expr = ctx.expr_ident(macsp, args_ident, args_hir_id);
+                let arg = ctx.arena.alloc(ctx.expr(
+                    sp,
+                    hir::ExprKind::Field(
+                        args_ident_expr,
+                        Ident::new(sym::integer(arg_index), macsp),
+                    ),
+                ));
+                make_argument(ctx, sp, arg, ty)
+            } else {
+                ctx.expr(macsp, hir::ExprKind::Err)
+            }
+        }));
+        let elements: Vec<_> = arguments
+            .iter()
+            .map(|arg| {
+                let arg_expr = ctx.lower_expr(&arg.expr);
+                ctx.expr(
+                    arg.expr.span.with_ctxt(macsp.ctxt()),
+                    hir::ExprKind::AddrOf(hir::BorrowKind::Ref, hir::Mutability::Not, arg_expr),
+                )
+            })
+            .collect();
+        let args_tuple = ctx
+            .arena
+            .alloc(ctx.expr(macsp, hir::ExprKind::Tup(ctx.arena.alloc_from_iter(elements))));
+        let array = ctx.arena.alloc(ctx.expr(macsp, hir::ExprKind::Array(args)));
+        let match_arms = ctx.arena.alloc_from_iter([ctx.arm(args_pat, array)]);
+        let match_expr = ctx.arena.alloc(ctx.expr_match(
+            macsp,
+            args_tuple,
+            match_arms,
+            hir::MatchSource::FormatArgs,
+        ));
+        ctx.expr(
+            macsp,
+            hir::ExprKind::AddrOf(hir::BorrowKind::Ref, hir::Mutability::Not, match_expr),
+        )
+    };
+
+    if let Some(format_options) = format_options {
+        // Generate:
+        //     <core::fmt::Arguments>::new_v1_formatted(
+        //         lit_pieces,
+        //         args,
+        //         format_options,
+        //         unsafe { ::core::fmt::UnsafeArg::new() }
+        //     )
+        let new_v1_formatted = ctx.arena.alloc(ctx.expr_lang_item_type_relative(
+            macsp,
+            hir::LangItem::FormatArguments,
+            sym::new_v1_formatted,
+        ));
+        let unsafe_arg_new = ctx.arena.alloc(ctx.expr_lang_item_type_relative(
+            macsp,
+            hir::LangItem::FormatUnsafeArg,
+            sym::new,
+        ));
+        let unsafe_arg_new_call = ctx.expr_call(macsp, unsafe_arg_new, &[]);
+        let hir_id = ctx.next_id();
+        let unsafe_arg = ctx.expr_block(ctx.arena.alloc(hir::Block {
+            stmts: &[],
+            expr: Some(unsafe_arg_new_call),
+            hir_id,
+            rules: hir::BlockCheckMode::UnsafeBlock(hir::UnsafeSource::CompilerGenerated),
+            span: macsp,
+            targeted_by_break: false,
+        }));
+        let args = ctx.arena.alloc_from_iter([lit_pieces, args, format_options, unsafe_arg]);
+        hir::ExprKind::Call(new_v1_formatted, args)
+    } else {
+        // Generate:
+        //     <core::fmt::Arguments>::new_v1(
+        //         lit_pieces,
+        //         args,
+        //     )
+        let new_v1 = ctx.arena.alloc(ctx.expr_lang_item_type_relative(
+            macsp,
+            hir::LangItem::FormatArguments,
+            sym::new_v1,
+        ));
+        let new_args = ctx.arena.alloc_from_iter([lit_pieces, args]);
+        hir::ExprKind::Call(new_v1, new_args)
+    }
+}
+
+fn may_contain_yield_point(e: &ast::Expr) -> bool {
+    struct MayContainYieldPoint(bool);
+
+    impl Visitor<'_> for MayContainYieldPoint {
+        fn visit_expr(&mut self, e: &ast::Expr) {
+            if let ast::ExprKind::Await(_) | ast::ExprKind::Yield(_) = e.kind {
+                self.0 = true;
+            } else {
+                visit::walk_expr(self, e);
+            }
+        }
+
+        fn visit_mac_call(&mut self, _: &ast::MacCall) {
+            // Macros should be expanded at this point.
+            unreachable!("unexpanded macro in ast lowering");
+        }
+
+        fn visit_item(&mut self, _: &ast::Item) {
+            // Do not recurse into nested items.
+        }
+    }
+
+    let mut visitor = MayContainYieldPoint(false);
+    visitor.visit_expr(e);
+    visitor.0
+}
index bc6d2cf12c78aaaeb80e5a50aa936f64cf49d8dd..35849a6b944e481591f8a451646bba6dfd7c0afe 100644 (file)
@@ -80,6 +80,7 @@ macro_rules! arena_vec {
 mod block;
 mod errors;
 mod expr;
+mod format;
 mod index;
 mod item;
 mod lifetime_collector;
@@ -416,6 +417,7 @@ fn compute_hir_hash(
 
 pub fn lower_to_hir(tcx: TyCtxt<'_>, (): ()) -> hir::Crate<'_> {
     let sess = tcx.sess;
+    tcx.ensure().output_filenames(());
     let (mut resolver, krate) = tcx.resolver_for_lowering(()).steal();
 
     let ast_index = index_crate(&resolver.node_id_to_def_id, &krate);
index a3e3e823b08eb5b677cafe36e84e8bbe2009cf42..b4900dc39a8af4d98913c75f26146923df617714 100644 (file)
@@ -6,5 +6,6 @@ edition = "2021"
 [lib]
 
 [dependencies]
-rustc_span = { path = "../rustc_span" }
 rustc_ast = { path = "../rustc_ast" }
+rustc_parse_format = { path = "../rustc_parse_format" }
+rustc_span = { path = "../rustc_span" }
index 2a18e5164a309bbb360ccae43d46565b4e83f9ff..99ffa19016f27e90891059d68262bfa9d05f21b5 100644 (file)
@@ -6,6 +6,8 @@
 use rustc_ast::util::literal::escape_byte_str_symbol;
 use rustc_ast::util::parser::{self, AssocOp, Fixity};
 use rustc_ast::{self as ast, BlockCheckMode};
+use rustc_ast::{FormatAlignment, FormatArgPosition, FormatArgsPiece, FormatCount, FormatTrait};
+use std::fmt::Write;
 
 impl<'a> State<'a> {
     fn print_else(&mut self, els: Option<&ast::Expr>) {
@@ -527,9 +529,23 @@ pub(super) fn print_expr_outer_attr_style(&mut self, expr: &ast::Expr, is_inline
                 }
             }
             ast::ExprKind::InlineAsm(a) => {
+                // FIXME: This should have its own syntax, distinct from a macro invocation.
                 self.word("asm!");
                 self.print_inline_asm(a);
             }
+            ast::ExprKind::FormatArgs(fmt) => {
+                // FIXME: This should have its own syntax, distinct from a macro invocation.
+                self.word("format_args!");
+                self.popen();
+                self.rbox(0, Inconsistent);
+                self.word(reconstruct_format_args_template_string(&fmt.template));
+                for arg in fmt.arguments.all_args() {
+                    self.word_space(",");
+                    self.print_expr(&arg.expr);
+                }
+                self.end();
+                self.pclose();
+            }
             ast::ExprKind::MacCall(m) => self.print_mac(m),
             ast::ExprKind::Paren(e) => {
                 self.popen();
@@ -629,3 +645,91 @@ fn print_capture_clause(&mut self, capture_clause: ast::CaptureBy) {
         }
     }
 }
+
+pub fn reconstruct_format_args_template_string(pieces: &[FormatArgsPiece]) -> String {
+    let mut template = "\"".to_string();
+    for piece in pieces {
+        match piece {
+            FormatArgsPiece::Literal(s) => {
+                for c in s.as_str().escape_debug() {
+                    template.push(c);
+                    if let '{' | '}' = c {
+                        template.push(c);
+                    }
+                }
+            }
+            FormatArgsPiece::Placeholder(p) => {
+                template.push('{');
+                let (Ok(n) | Err(n)) = p.argument.index;
+                write!(template, "{n}").unwrap();
+                if p.format_options != Default::default() || p.format_trait != FormatTrait::Display
+                {
+                    template.push_str(":");
+                }
+                if let Some(fill) = p.format_options.fill {
+                    template.push(fill);
+                }
+                match p.format_options.alignment {
+                    Some(FormatAlignment::Left) => template.push_str("<"),
+                    Some(FormatAlignment::Right) => template.push_str(">"),
+                    Some(FormatAlignment::Center) => template.push_str("^"),
+                    None => {}
+                }
+                let flags = p.format_options.flags;
+                if flags >> (rustc_parse_format::FlagSignPlus as usize) & 1 != 0 {
+                    template.push('+');
+                }
+                if flags >> (rustc_parse_format::FlagSignMinus as usize) & 1 != 0 {
+                    template.push('-');
+                }
+                if flags >> (rustc_parse_format::FlagAlternate as usize) & 1 != 0 {
+                    template.push('#');
+                }
+                if flags >> (rustc_parse_format::FlagSignAwareZeroPad as usize) & 1 != 0 {
+                    template.push('0');
+                }
+                if let Some(width) = &p.format_options.width {
+                    match width {
+                        FormatCount::Literal(n) => write!(template, "{n}").unwrap(),
+                        FormatCount::Argument(FormatArgPosition {
+                            index: Ok(n) | Err(n), ..
+                        }) => {
+                            write!(template, "{n}$").unwrap();
+                        }
+                    }
+                }
+                if let Some(precision) = &p.format_options.precision {
+                    template.push('.');
+                    match precision {
+                        FormatCount::Literal(n) => write!(template, "{n}").unwrap(),
+                        FormatCount::Argument(FormatArgPosition {
+                            index: Ok(n) | Err(n), ..
+                        }) => {
+                            write!(template, "{n}$").unwrap();
+                        }
+                    }
+                }
+                if flags >> (rustc_parse_format::FlagDebugLowerHex as usize) & 1 != 0 {
+                    template.push('x');
+                }
+                if flags >> (rustc_parse_format::FlagDebugUpperHex as usize) & 1 != 0 {
+                    template.push('X');
+                }
+                template.push_str(match p.format_trait {
+                    FormatTrait::Display => "",
+                    FormatTrait::Debug => "?",
+                    FormatTrait::LowerExp => "e",
+                    FormatTrait::UpperExp => "E",
+                    FormatTrait::Octal => "o",
+                    FormatTrait::Pointer => "p",
+                    FormatTrait::Binary => "b",
+                    FormatTrait::LowerHex => "x",
+                    FormatTrait::UpperHex => "X",
+                });
+                template.push('}');
+            }
+        }
+    }
+    template.push('"');
+    template
+}
index a4943d112042dc212d419f0247933a88cecb158a..2bbb9618dbf09f27f74a09662e66c6fffd6dd031 100644 (file)
@@ -37,7 +37,7 @@ pub(crate) fn cannot_use_when_mutably_borrowed(
             desc,
         );
 
-        err.span_label(borrow_span, format!("borrow of {} occurs here", borrow_desc));
+        err.span_label(borrow_span, format!("{} is borrowed here", borrow_desc));
         err.span_label(span, format!("use of borrowed {}", borrow_desc));
         err
     }
@@ -250,8 +250,8 @@ pub(crate) fn cannot_assign_to_borrowed(
             desc,
         );
 
-        err.span_label(borrow_span, format!("borrow of {} occurs here", desc));
-        err.span_label(span, format!("assignment to borrowed {} occurs here", desc));
+        err.span_label(borrow_span, format!("{} is borrowed here", desc));
+        err.span_label(span, format!("{} is assigned to here but it was already borrowed", desc));
         err
     }
 
index e5a36259fa495c0abdff6188e8dc5862499dbdbe..a1eb2960d7b7c98d16bf2521ddfd30ac4ccd5b38 100644 (file)
@@ -766,7 +766,7 @@ fn suggest_adding_copy_bounds(&self, err: &mut Diagnostic, ty: Ty<'tcx>, span: S
         let copy_did = infcx.tcx.require_lang_item(LangItem::Copy, Some(span));
         let cause = ObligationCause::new(
             span,
-            self.mir_hir_id(),
+            self.mir_def_id(),
             rustc_infer::traits::ObligationCauseCode::MiscObligation,
         );
         let errors = rustc_trait_selection::traits::fully_solve_bound(
@@ -1736,7 +1736,7 @@ fn report_local_value_does_not_live_long_enough(
                 &self.local_names,
                 &mut err,
                 "",
-                None,
+                Some(borrow_span),
                 None,
             );
         }
index 2095747097b7660870ecdff8b32fc8820525652b..19855075ced80d7383d01be49f5d4e5dc946aedd 100644 (file)
@@ -1,6 +1,8 @@
 //! Print diagnostics to explain why values are borrowed.
 
 use rustc_errors::{Applicability, Diagnostic};
+use rustc_hir as hir;
+use rustc_hir::intravisit::Visitor;
 use rustc_index::vec::IndexVec;
 use rustc_infer::infer::NllRegionVariableOrigin;
 use rustc_middle::mir::{
@@ -11,6 +13,7 @@
 use rustc_middle::ty::{self, RegionVid, TyCtxt};
 use rustc_span::symbol::{kw, Symbol};
 use rustc_span::{sym, DesugaringKind, Span};
+use rustc_trait_selection::traits::error_reporting::FindExprBySpan;
 
 use crate::region_infer::{BlameConstraint, ExtraConstraintInfo};
 use crate::{
@@ -63,6 +66,36 @@ pub(crate) fn add_explanation_to_diagnostic(
         borrow_span: Option<Span>,
         multiple_borrow_span: Option<(Span, Span)>,
     ) {
+        if let Some(span) = borrow_span {
+            let def_id = body.source.def_id();
+            if let Some(node) = tcx.hir().get_if_local(def_id)
+                && let Some(body_id) = node.body_id()
+            {
+                let body = tcx.hir().body(body_id);
+                let mut expr_finder = FindExprBySpan::new(span);
+                expr_finder.visit_expr(body.value);
+                if let Some(mut expr) = expr_finder.result {
+                    while let hir::ExprKind::AddrOf(_, _, inner)
+                        | hir::ExprKind::Unary(hir::UnOp::Deref, inner)
+                        | hir::ExprKind::Field(inner, _)
+                        | hir::ExprKind::MethodCall(_, inner, _, _)
+                        | hir::ExprKind::Index(inner, _) = &expr.kind
+                    {
+                        expr = inner;
+                    }
+                    if let hir::ExprKind::Path(hir::QPath::Resolved(None, p)) = expr.kind
+                        && let [hir::PathSegment { ident, args: None, .. }] = p.segments
+                        && let hir::def::Res::Local(hir_id) = p.res
+                        && let Some(hir::Node::Pat(pat)) = tcx.hir().find(hir_id)
+                    {
+                        err.span_label(
+                            pat.span,
+                            &format!("binding `{ident}` declared here"),
+                        );
+                    }
+                }
+            }
+        }
         match *self {
             BorrowExplanation::UsedLater(later_use_kind, var_or_use_span, path_span) => {
                 let message = match later_use_kind {
index 6db3c858ae7149b9a138dbd77c7813c3eeea298e..ea58ad5ae3e34539a7ee5bf53f2ec95ffa7a8a3e 100644 (file)
@@ -448,7 +448,7 @@ fn add_move_hints(&self, error: GroupedMoveError<'tcx>, err: &mut Diagnostic, sp
                 };
                 self.note_type_does_not_implement_copy(err, &place_desc, place_ty, Some(span), "");
 
-                use_spans.args_span_label(err, format!("move out of {place_desc} occurs here"));
+                use_spans.args_span_label(err, format!("{place_desc} is moved here"));
             }
         }
     }
index 187861ba127bd93e36af2707722146eee40ff574..87db08ef5b5108e3b6439883ce5d8bb869f90967 100644 (file)
@@ -813,17 +813,10 @@ fn add_static_impl_trait_suggestion(
             if *outlived_f != ty::ReStatic {
                 return;
             }
+            let suitable_region = self.infcx.tcx.is_suitable_region(f);
+            let Some(suitable_region) = suitable_region else { return; };
 
-            let fn_returns = self
-                .infcx
-                .tcx
-                .is_suitable_region(f)
-                .map(|r| self.infcx.tcx.return_type_impl_or_dyn_traits(r.def_id))
-                .unwrap_or_default();
-
-            if fn_returns.is_empty() {
-                return;
-            }
+            let fn_returns = self.infcx.tcx.return_type_impl_or_dyn_traits(suitable_region.def_id);
 
             let param = if let Some(param) = find_param_with_region(self.infcx.tcx, f, outlived_f) {
                 param
@@ -839,15 +832,43 @@ fn add_static_impl_trait_suggestion(
             };
             let captures = format!("captures data from {arg}");
 
-            return nice_region_error::suggest_new_region_bound(
-                self.infcx.tcx,
-                diag,
-                fn_returns,
-                lifetime.to_string(),
-                Some(arg),
-                captures,
-                Some((param.param_ty_span, param.param_ty.to_string())),
-                self.infcx.tcx.is_suitable_region(f).map(|r| r.def_id),
+            if !fn_returns.is_empty() {
+                nice_region_error::suggest_new_region_bound(
+                    self.infcx.tcx,
+                    diag,
+                    fn_returns,
+                    lifetime.to_string(),
+                    Some(arg),
+                    captures,
+                    Some((param.param_ty_span, param.param_ty.to_string())),
+                    Some(suitable_region.def_id),
+                );
+                return;
+            }
+
+            let Some((alias_tys, alias_span)) = self
+                .infcx
+                .tcx
+                .return_type_impl_or_dyn_traits_with_type_alias(suitable_region.def_id) else { return; };
+
+            // in case the return type of the method is a type alias
+            let mut spans_suggs: Vec<_> = Vec::new();
+            for alias_ty in alias_tys {
+                if alias_ty.span.desugaring_kind().is_some() {
+                    // Skip `async` desugaring `impl Future`.
+                    ()
+                }
+                if let TyKind::TraitObject(_, lt, _) = alias_ty.kind {
+                    spans_suggs.push((lt.ident.span.shrink_to_hi(), " + 'a".to_string()));
+                }
+            }
+            spans_suggs.push((alias_span.shrink_to_hi(), "<'a>".to_string()));
+            diag.multipart_suggestion_verbose(
+                &format!(
+                    "to declare that the trait object {captures}, you can add a lifetime parameter `'a` in the type alias"
+                ),
+                spans_suggs,
+                Applicability::MaybeIncorrect,
             );
         }
     }
index 238172ea3992f5a08b2cac2f0f00b1659d67ae02..2ae13990a4589834128aea43c4b98bbe0f5d0ef3 100644 (file)
@@ -7,7 +7,6 @@
 use rustc_data_structures::graph::scc::Sccs;
 use rustc_errors::Diagnostic;
 use rustc_hir::def_id::CRATE_DEF_ID;
-use rustc_hir::CRATE_HIR_ID;
 use rustc_index::vec::IndexVec;
 use rustc_infer::infer::outlives::test_type_match;
 use rustc_infer::infer::region_constraints::{GenericKind, VarInfos, VerifyBound, VerifyIfEq};
@@ -2022,7 +2021,7 @@ pub(crate) fn best_blame_constraint(
             .map(|constraint| BlameConstraint {
                 category: constraint.category,
                 from_closure: constraint.from_closure,
-                cause: ObligationCause::new(constraint.span, CRATE_HIR_ID, cause_code.clone()),
+                cause: ObligationCause::new(constraint.span, CRATE_DEF_ID, cause_code.clone()),
                 variance_info: constraint.variance_info,
                 outlives_constraint: *constraint,
             })
index db5a67a8b442d97e13678b8262a7f2cdc197580d..e0e814cfc0ac812e94655a920a909da4809555bb 100644 (file)
@@ -273,7 +273,6 @@ fn infer_opaque_definition_from_instantiation(
         // This logic duplicates most of `check_opaque_meets_bounds`.
         // FIXME(oli-obk): Also do region checks here and then consider removing `check_opaque_meets_bounds` entirely.
         let param_env = self.tcx.param_env(def_id);
-        let body_id = self.tcx.local_def_id_to_hir_id(def_id);
         // HACK This bubble is required for this tests to pass:
         // type-alias-impl-trait/issue-67844-nested-opaque.rs
         let infcx =
@@ -290,7 +289,7 @@ fn infer_opaque_definition_from_instantiation(
         // the bounds that the function supplies.
         let opaque_ty = self.tcx.mk_opaque(def_id.to_def_id(), id_substs);
         if let Err(err) = ocx.eq(
-            &ObligationCause::misc(instantiated_ty.span, body_id),
+            &ObligationCause::misc(instantiated_ty.span, def_id),
             param_env,
             opaque_ty,
             definition_ty,
@@ -298,7 +297,7 @@ fn infer_opaque_definition_from_instantiation(
             infcx
                 .err_ctxt()
                 .report_mismatched_types(
-                    &ObligationCause::misc(instantiated_ty.span, body_id),
+                    &ObligationCause::misc(instantiated_ty.span, def_id),
                     opaque_ty,
                     definition_ty,
                     err,
@@ -309,7 +308,7 @@ fn infer_opaque_definition_from_instantiation(
         ocx.register_obligation(Obligation::misc(
             infcx.tcx,
             instantiated_ty.span,
-            body_id,
+            def_id,
             param_env,
             predicate,
         ));
@@ -368,18 +367,6 @@ fn check_opaque_type_parameter_valid(
     for (i, arg) in opaque_type_key.substs.iter().enumerate() {
         let arg_is_param = match arg.unpack() {
             GenericArgKind::Type(ty) => matches!(ty.kind(), ty::Param(_)),
-            GenericArgKind::Lifetime(lt) if lt.is_static() => {
-                tcx.sess
-                    .struct_span_err(span, "non-defining opaque type use in defining scope")
-                    .span_label(
-                        tcx.def_span(opaque_generics.param_at(i, tcx).def_id),
-                        "cannot use static lifetime; use a bound lifetime \
-                                    instead or remove the lifetime parameter from the \
-                                    opaque type",
-                    )
-                    .emit();
-                return false;
-            }
             GenericArgKind::Lifetime(lt) => {
                 matches!(*lt, ty::ReEarlyBound(_) | ty::ReFree(_))
             }
index 93b07801e035d7de24d995980ccd1568063ffb29..342b1735661df9acd779fdf54fc6f7fc6154174c 100644 (file)
@@ -297,6 +297,7 @@ fn manage_cond_expr(&mut self, expr: &mut P<Expr>) {
             | ExprKind::Continue(_)
             | ExprKind::Err
             | ExprKind::Field(_, _)
+            | ExprKind::FormatArgs(_)
             | ExprKind::ForLoop(_, _, _, _)
             | ExprKind::If(_, _, _)
             | ExprKind::IncludedBytes(..)
index 9f4bbbc62c819e516273c409c89eeec3fc72877a..469f0dc130383cb17b87d1010b2439330e884b7a 100644 (file)
@@ -1,7 +1,11 @@
 use rustc_ast::ptr::P;
 use rustc_ast::token;
 use rustc_ast::tokenstream::TokenStream;
-use rustc_ast::Expr;
+use rustc_ast::{
+    Expr, ExprKind, FormatAlignment, FormatArgPosition, FormatArgPositionKind, FormatArgs,
+    FormatArgsPiece, FormatArgument, FormatArgumentKind, FormatArguments, FormatCount,
+    FormatOptions, FormatPlaceholder, FormatTrait,
+};
 use rustc_data_structures::fx::FxHashSet;
 use rustc_errors::{pluralize, Applicability, MultiSpan, PResult};
 use rustc_expand::base::{self, *};
 use rustc_lint_defs::builtin::NAMED_ARGUMENTS_USED_POSITIONALLY;
 use rustc_lint_defs::{BufferedEarlyLint, BuiltinLintDiagnostics, LintId};
 
-mod ast;
-use ast::*;
-
-mod expand;
-use expand::expand_parsed_format_args;
-
 // The format_args!() macro is expanded in three steps:
 //  1. First, `parse_args` will parse the `(literal, arg, arg, name=arg, name=arg)` syntax,
 //     but doesn't parse the template (the literal) itself.
 //  2. Second, `make_format_args` will parse the template, the format options, resolve argument references,
-//     produce diagnostics, and turn the whole thing into a `FormatArgs` structure.
-//  3. Finally, `expand_parsed_format_args` will turn that `FormatArgs` structure
-//     into the expression that the macro expands to.
+//     produce diagnostics, and turn the whole thing into a `FormatArgs` AST node.
+//  3. Much later, in AST lowering (rustc_ast_lowering), that `FormatArgs` structure will be turned
+//     into the expression of type `core::fmt::Arguments`.
 
-// See format/ast.rs for the FormatArgs structure and glossary.
+// See rustc_ast/src/format.rs for the FormatArgs structure and glossary.
 
 // Only used in parse_args and report_invalid_references,
 // to indicate how a referred argument was used.
@@ -850,7 +848,7 @@ fn expand_format_args_impl<'cx>(
     match parse_args(ecx, sp, tts) {
         Ok((efmt, args)) => {
             if let Ok(format_args) = make_format_args(ecx, efmt, args, nl) {
-                MacEager::expr(expand_parsed_format_args(ecx, format_args))
+                MacEager::expr(ecx.expr(sp, ExprKind::FormatArgs(P(format_args))))
             } else {
                 MacEager::expr(DummyResult::raw_expr(sp, true))
             }
diff --git a/compiler/rustc_builtin_macros/src/format/ast.rs b/compiler/rustc_builtin_macros/src/format/ast.rs
deleted file mode 100644 (file)
index 01dbffa..0000000
+++ /dev/null
@@ -1,240 +0,0 @@
-use rustc_ast::ptr::P;
-use rustc_ast::Expr;
-use rustc_data_structures::fx::FxHashMap;
-use rustc_span::symbol::{Ident, Symbol};
-use rustc_span::Span;
-
-// Definitions:
-//
-// format_args!("hello {abc:.xyz$}!!", abc="world");
-// └──────────────────────────────────────────────┘
-//                     FormatArgs
-//
-// format_args!("hello {abc:.xyz$}!!", abc="world");
-//                                     └─────────┘
-//                                      argument
-//
-// format_args!("hello {abc:.xyz$}!!", abc="world");
-//              └───────────────────┘
-//                     template
-//
-// format_args!("hello {abc:.xyz$}!!", abc="world");
-//               └────┘└─────────┘└┘
-//                      pieces
-//
-// format_args!("hello {abc:.xyz$}!!", abc="world");
-//               └────┘           └┘
-//                   literal pieces
-//
-// format_args!("hello {abc:.xyz$}!!", abc="world");
-//                     └─────────┘
-//                     placeholder
-//
-// format_args!("hello {abc:.xyz$}!!", abc="world");
-//                      └─┘  └─┘
-//                      positions (could be names, numbers, empty, or `*`)
-
-/// (Parsed) format args.
-///
-/// Basically the "AST" for a complete `format_args!()`.
-///
-/// E.g., `format_args!("hello {name}");`.
-#[derive(Clone, Debug)]
-pub struct FormatArgs {
-    pub span: Span,
-    pub template: Vec<FormatArgsPiece>,
-    pub arguments: FormatArguments,
-}
-
-/// A piece of a format template string.
-///
-/// E.g. "hello" or "{name}".
-#[derive(Clone, Debug)]
-pub enum FormatArgsPiece {
-    Literal(Symbol),
-    Placeholder(FormatPlaceholder),
-}
-
-/// The arguments to format_args!().
-///
-/// E.g. `1, 2, name="ferris", n=3`,
-/// but also implicit captured arguments like `x` in `format_args!("{x}")`.
-#[derive(Clone, Debug)]
-pub struct FormatArguments {
-    arguments: Vec<FormatArgument>,
-    num_unnamed_args: usize,
-    num_explicit_args: usize,
-    names: FxHashMap<Symbol, usize>,
-}
-
-impl FormatArguments {
-    pub fn new() -> Self {
-        Self {
-            arguments: Vec::new(),
-            names: FxHashMap::default(),
-            num_unnamed_args: 0,
-            num_explicit_args: 0,
-        }
-    }
-
-    pub fn add(&mut self, arg: FormatArgument) -> usize {
-        let index = self.arguments.len();
-        if let Some(name) = arg.kind.ident() {
-            self.names.insert(name.name, index);
-        } else if self.names.is_empty() {
-            // Only count the unnamed args before the first named arg.
-            // (Any later ones are errors.)
-            self.num_unnamed_args += 1;
-        }
-        if !matches!(arg.kind, FormatArgumentKind::Captured(..)) {
-            // This is an explicit argument.
-            // Make sure that all arguments so far are explcit.
-            assert_eq!(
-                self.num_explicit_args,
-                self.arguments.len(),
-                "captured arguments must be added last"
-            );
-            self.num_explicit_args += 1;
-        }
-        self.arguments.push(arg);
-        index
-    }
-
-    pub fn by_name(&self, name: Symbol) -> Option<(usize, &FormatArgument)> {
-        let i = *self.names.get(&name)?;
-        Some((i, &self.arguments[i]))
-    }
-
-    pub fn by_index(&self, i: usize) -> Option<&FormatArgument> {
-        (i < self.num_explicit_args).then(|| &self.arguments[i])
-    }
-
-    pub fn unnamed_args(&self) -> &[FormatArgument] {
-        &self.arguments[..self.num_unnamed_args]
-    }
-
-    pub fn named_args(&self) -> &[FormatArgument] {
-        &self.arguments[self.num_unnamed_args..self.num_explicit_args]
-    }
-
-    pub fn explicit_args(&self) -> &[FormatArgument] {
-        &self.arguments[..self.num_explicit_args]
-    }
-
-    pub fn into_vec(self) -> Vec<FormatArgument> {
-        self.arguments
-    }
-}
-
-#[derive(Clone, Debug)]
-pub struct FormatArgument {
-    pub kind: FormatArgumentKind,
-    pub expr: P<Expr>,
-}
-
-#[derive(Clone, Debug)]
-pub enum FormatArgumentKind {
-    /// `format_args(…, arg)`
-    Normal,
-    /// `format_args(…, arg = 1)`
-    Named(Ident),
-    /// `format_args("… {arg} …")`
-    Captured(Ident),
-}
-
-impl FormatArgumentKind {
-    pub fn ident(&self) -> Option<Ident> {
-        match self {
-            &Self::Normal => None,
-            &Self::Named(id) => Some(id),
-            &Self::Captured(id) => Some(id),
-        }
-    }
-}
-
-#[derive(Clone, Debug, PartialEq, Eq)]
-pub struct FormatPlaceholder {
-    /// Index into [`FormatArgs::arguments`].
-    pub argument: FormatArgPosition,
-    /// The span inside the format string for the full `{…}` placeholder.
-    pub span: Option<Span>,
-    /// `{}`, `{:?}`, or `{:x}`, etc.
-    pub format_trait: FormatTrait,
-    /// `{}` or `{:.5}` or `{:-^20}`, etc.
-    pub format_options: FormatOptions,
-}
-
-#[derive(Clone, Debug, PartialEq, Eq)]
-pub struct FormatArgPosition {
-    /// Which argument this position refers to (Ok),
-    /// or would've referred to if it existed (Err).
-    pub index: Result<usize, usize>,
-    /// What kind of position this is. See [`FormatArgPositionKind`].
-    pub kind: FormatArgPositionKind,
-    /// The span of the name or number.
-    pub span: Option<Span>,
-}
-
-#[derive(Copy, Clone, Debug, PartialEq, Eq)]
-pub enum FormatArgPositionKind {
-    /// `{}` or `{:.*}`
-    Implicit,
-    /// `{1}` or `{:1$}` or `{:.1$}`
-    Number,
-    /// `{a}` or `{:a$}` or `{:.a$}`
-    Named,
-}
-
-#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
-pub enum FormatTrait {
-    /// `{}`
-    Display,
-    /// `{:?}`
-    Debug,
-    /// `{:e}`
-    LowerExp,
-    /// `{:E}`
-    UpperExp,
-    /// `{:o}`
-    Octal,
-    /// `{:p}`
-    Pointer,
-    /// `{:b}`
-    Binary,
-    /// `{:x}`
-    LowerHex,
-    /// `{:X}`
-    UpperHex,
-}
-
-#[derive(Clone, Debug, Default, PartialEq, Eq)]
-pub struct FormatOptions {
-    /// The width. E.g. `{:5}` or `{:width$}`.
-    pub width: Option<FormatCount>,
-    /// The precision. E.g. `{:.5}` or `{:.precision$}`.
-    pub precision: Option<FormatCount>,
-    /// The alignment. E.g. `{:>}` or `{:<}` or `{:^}`.
-    pub alignment: Option<FormatAlignment>,
-    /// The fill character. E.g. the `.` in `{:.>10}`.
-    pub fill: Option<char>,
-    /// The `+`, `-`, `0`, `#`, `x?` and `X?` flags.
-    pub flags: u32,
-}
-
-#[derive(Clone, Debug, PartialEq, Eq)]
-pub enum FormatAlignment {
-    /// `{:<}`
-    Left,
-    /// `{:>}`
-    Right,
-    /// `{:^}`
-    Center,
-}
-
-#[derive(Clone, Debug, PartialEq, Eq)]
-pub enum FormatCount {
-    /// `{:5}` or `{:.5}`
-    Literal(usize),
-    /// `{:.*}`, `{:.5$}`, or `{:a$}`, etc.
-    Argument(FormatArgPosition),
-}
diff --git a/compiler/rustc_builtin_macros/src/format/expand.rs b/compiler/rustc_builtin_macros/src/format/expand.rs
deleted file mode 100644 (file)
index 9dde5ef..0000000
+++ /dev/null
@@ -1,353 +0,0 @@
-use super::*;
-use rustc_ast as ast;
-use rustc_ast::visit::{self, Visitor};
-use rustc_ast::{BlockCheckMode, UnsafeSource};
-use rustc_data_structures::fx::FxIndexSet;
-use rustc_span::{sym, symbol::kw};
-
-#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
-enum ArgumentType {
-    Format(FormatTrait),
-    Usize,
-}
-
-fn make_argument(ecx: &ExtCtxt<'_>, sp: Span, arg: P<ast::Expr>, ty: ArgumentType) -> P<ast::Expr> {
-    // Generate:
-    //     ::core::fmt::ArgumentV1::new_…(arg)
-    use ArgumentType::*;
-    use FormatTrait::*;
-    ecx.expr_call_global(
-        sp,
-        ecx.std_path(&[
-            sym::fmt,
-            sym::ArgumentV1,
-            match ty {
-                Format(Display) => sym::new_display,
-                Format(Debug) => sym::new_debug,
-                Format(LowerExp) => sym::new_lower_exp,
-                Format(UpperExp) => sym::new_upper_exp,
-                Format(Octal) => sym::new_octal,
-                Format(Pointer) => sym::new_pointer,
-                Format(Binary) => sym::new_binary,
-                Format(LowerHex) => sym::new_lower_hex,
-                Format(UpperHex) => sym::new_upper_hex,
-                Usize => sym::from_usize,
-            },
-        ]),
-        vec![arg],
-    )
-}
-
-fn make_count(
-    ecx: &ExtCtxt<'_>,
-    sp: Span,
-    count: &Option<FormatCount>,
-    argmap: &mut FxIndexSet<(usize, ArgumentType)>,
-) -> P<ast::Expr> {
-    // Generate:
-    //     ::core::fmt::rt::v1::Count::…(…)
-    match count {
-        Some(FormatCount::Literal(n)) => ecx.expr_call_global(
-            sp,
-            ecx.std_path(&[sym::fmt, sym::rt, sym::v1, sym::Count, sym::Is]),
-            vec![ecx.expr_usize(sp, *n)],
-        ),
-        Some(FormatCount::Argument(arg)) => {
-            if let Ok(arg_index) = arg.index {
-                let (i, _) = argmap.insert_full((arg_index, ArgumentType::Usize));
-                ecx.expr_call_global(
-                    sp,
-                    ecx.std_path(&[sym::fmt, sym::rt, sym::v1, sym::Count, sym::Param]),
-                    vec![ecx.expr_usize(sp, i)],
-                )
-            } else {
-                DummyResult::raw_expr(sp, true)
-            }
-        }
-        None => ecx.expr_path(ecx.path_global(
-            sp,
-            ecx.std_path(&[sym::fmt, sym::rt, sym::v1, sym::Count, sym::Implied]),
-        )),
-    }
-}
-
-fn make_format_spec(
-    ecx: &ExtCtxt<'_>,
-    sp: Span,
-    placeholder: &FormatPlaceholder,
-    argmap: &mut FxIndexSet<(usize, ArgumentType)>,
-) -> P<ast::Expr> {
-    // Generate:
-    //     ::core::fmt::rt::v1::Argument {
-    //         position: 0usize,
-    //         format: ::core::fmt::rt::v1::FormatSpec {
-    //             fill: ' ',
-    //             align: ::core::fmt::rt::v1::Alignment::Unknown,
-    //             flags: 0u32,
-    //             precision: ::core::fmt::rt::v1::Count::Implied,
-    //             width: ::core::fmt::rt::v1::Count::Implied,
-    //         },
-    //     }
-    let position = match placeholder.argument.index {
-        Ok(arg_index) => {
-            let (i, _) =
-                argmap.insert_full((arg_index, ArgumentType::Format(placeholder.format_trait)));
-            ecx.expr_usize(sp, i)
-        }
-        Err(_) => DummyResult::raw_expr(sp, true),
-    };
-    let fill = ecx.expr_char(sp, placeholder.format_options.fill.unwrap_or(' '));
-    let align = ecx.expr_path(ecx.path_global(
-        sp,
-        ecx.std_path(&[
-            sym::fmt,
-            sym::rt,
-            sym::v1,
-            sym::Alignment,
-            match placeholder.format_options.alignment {
-                Some(FormatAlignment::Left) => sym::Left,
-                Some(FormatAlignment::Right) => sym::Right,
-                Some(FormatAlignment::Center) => sym::Center,
-                None => sym::Unknown,
-            },
-        ]),
-    ));
-    let flags = ecx.expr_u32(sp, placeholder.format_options.flags);
-    let prec = make_count(ecx, sp, &placeholder.format_options.precision, argmap);
-    let width = make_count(ecx, sp, &placeholder.format_options.width, argmap);
-    ecx.expr_struct(
-        sp,
-        ecx.path_global(sp, ecx.std_path(&[sym::fmt, sym::rt, sym::v1, sym::Argument])),
-        vec![
-            ecx.field_imm(sp, Ident::new(sym::position, sp), position),
-            ecx.field_imm(
-                sp,
-                Ident::new(sym::format, sp),
-                ecx.expr_struct(
-                    sp,
-                    ecx.path_global(
-                        sp,
-                        ecx.std_path(&[sym::fmt, sym::rt, sym::v1, sym::FormatSpec]),
-                    ),
-                    vec![
-                        ecx.field_imm(sp, Ident::new(sym::fill, sp), fill),
-                        ecx.field_imm(sp, Ident::new(sym::align, sp), align),
-                        ecx.field_imm(sp, Ident::new(sym::flags, sp), flags),
-                        ecx.field_imm(sp, Ident::new(sym::precision, sp), prec),
-                        ecx.field_imm(sp, Ident::new(sym::width, sp), width),
-                    ],
-                ),
-            ),
-        ],
-    )
-}
-
-pub fn expand_parsed_format_args(ecx: &mut ExtCtxt<'_>, fmt: FormatArgs) -> P<ast::Expr> {
-    let macsp = ecx.with_def_site_ctxt(ecx.call_site());
-
-    let lit_pieces = ecx.expr_array_ref(
-        fmt.span,
-        fmt.template
-            .iter()
-            .enumerate()
-            .filter_map(|(i, piece)| match piece {
-                &FormatArgsPiece::Literal(s) => Some(ecx.expr_str(fmt.span, s)),
-                &FormatArgsPiece::Placeholder(_) => {
-                    // Inject empty string before placeholders when not already preceded by a literal piece.
-                    if i == 0 || matches!(fmt.template[i - 1], FormatArgsPiece::Placeholder(_)) {
-                        Some(ecx.expr_str(fmt.span, kw::Empty))
-                    } else {
-                        None
-                    }
-                }
-            })
-            .collect(),
-    );
-
-    // Whether we'll use the `Arguments::new_v1_formatted` form (true),
-    // or the `Arguments::new_v1` form (false).
-    let mut use_format_options = false;
-
-    // Create a list of all _unique_ (argument, format trait) combinations.
-    // E.g. "{0} {0:x} {0} {1}" -> [(0, Display), (0, LowerHex), (1, Display)]
-    let mut argmap = FxIndexSet::default();
-    for piece in &fmt.template {
-        let FormatArgsPiece::Placeholder(placeholder) = piece else { continue };
-        if placeholder.format_options != Default::default() {
-            // Can't use basic form if there's any formatting options.
-            use_format_options = true;
-        }
-        if let Ok(index) = placeholder.argument.index {
-            if !argmap.insert((index, ArgumentType::Format(placeholder.format_trait))) {
-                // Duplicate (argument, format trait) combination,
-                // which we'll only put once in the args array.
-                use_format_options = true;
-            }
-        }
-    }
-
-    let format_options = use_format_options.then(|| {
-        // Generate:
-        //     &[format_spec_0, format_spec_1, format_spec_2]
-        ecx.expr_array_ref(
-            macsp,
-            fmt.template
-                .iter()
-                .filter_map(|piece| {
-                    let FormatArgsPiece::Placeholder(placeholder) = piece else { return None };
-                    Some(make_format_spec(ecx, macsp, placeholder, &mut argmap))
-                })
-                .collect(),
-        )
-    });
-
-    let arguments = fmt.arguments.into_vec();
-
-    // If the args array contains exactly all the original arguments once,
-    // in order, we can use a simple array instead of a `match` construction.
-    // However, if there's a yield point in any argument except the first one,
-    // we don't do this, because an ArgumentV1 cannot be kept across yield points.
-    let use_simple_array = argmap.len() == arguments.len()
-        && argmap.iter().enumerate().all(|(i, &(j, _))| i == j)
-        && arguments.iter().skip(1).all(|arg| !may_contain_yield_point(&arg.expr));
-
-    let args = if use_simple_array {
-        // Generate:
-        //     &[
-        //         ::core::fmt::ArgumentV1::new_display(&arg0),
-        //         ::core::fmt::ArgumentV1::new_lower_hex(&arg1),
-        //         ::core::fmt::ArgumentV1::new_debug(&arg2),
-        //     ]
-        ecx.expr_array_ref(
-            macsp,
-            arguments
-                .into_iter()
-                .zip(argmap)
-                .map(|(arg, (_, ty))| {
-                    let sp = arg.expr.span.with_ctxt(macsp.ctxt());
-                    make_argument(ecx, sp, ecx.expr_addr_of(sp, arg.expr), ty)
-                })
-                .collect(),
-        )
-    } else {
-        // Generate:
-        //     match (&arg0, &arg1, &arg2) {
-        //         args => &[
-        //             ::core::fmt::ArgumentV1::new_display(args.0),
-        //             ::core::fmt::ArgumentV1::new_lower_hex(args.1),
-        //             ::core::fmt::ArgumentV1::new_debug(args.0),
-        //         ]
-        //     }
-        let args_ident = Ident::new(sym::args, macsp);
-        let args = argmap
-            .iter()
-            .map(|&(arg_index, ty)| {
-                if let Some(arg) = arguments.get(arg_index) {
-                    let sp = arg.expr.span.with_ctxt(macsp.ctxt());
-                    make_argument(
-                        ecx,
-                        sp,
-                        ecx.expr_field(
-                            sp,
-                            ecx.expr_ident(macsp, args_ident),
-                            Ident::new(sym::integer(arg_index), macsp),
-                        ),
-                        ty,
-                    )
-                } else {
-                    DummyResult::raw_expr(macsp, true)
-                }
-            })
-            .collect();
-        ecx.expr_addr_of(
-            macsp,
-            ecx.expr_match(
-                macsp,
-                ecx.expr_tuple(
-                    macsp,
-                    arguments
-                        .into_iter()
-                        .map(|arg| {
-                            ecx.expr_addr_of(arg.expr.span.with_ctxt(macsp.ctxt()), arg.expr)
-                        })
-                        .collect(),
-                ),
-                vec![ecx.arm(macsp, ecx.pat_ident(macsp, args_ident), ecx.expr_array(macsp, args))],
-            ),
-        )
-    };
-
-    if let Some(format_options) = format_options {
-        // Generate:
-        //     ::core::fmt::Arguments::new_v1_formatted(
-        //         lit_pieces,
-        //         args,
-        //         format_options,
-        //         unsafe { ::core::fmt::UnsafeArg::new() }
-        //     )
-        ecx.expr_call_global(
-            macsp,
-            ecx.std_path(&[sym::fmt, sym::Arguments, sym::new_v1_formatted]),
-            vec![
-                lit_pieces,
-                args,
-                format_options,
-                ecx.expr_block(P(ast::Block {
-                    stmts: vec![ecx.stmt_expr(ecx.expr_call_global(
-                        macsp,
-                        ecx.std_path(&[sym::fmt, sym::UnsafeArg, sym::new]),
-                        Vec::new(),
-                    ))],
-                    id: ast::DUMMY_NODE_ID,
-                    rules: BlockCheckMode::Unsafe(UnsafeSource::CompilerGenerated),
-                    span: macsp,
-                    tokens: None,
-                    could_be_bare_literal: false,
-                })),
-            ],
-        )
-    } else {
-        // Generate:
-        //     ::core::fmt::Arguments::new_v1(
-        //         lit_pieces,
-        //         args,
-        //     )
-        ecx.expr_call_global(
-            macsp,
-            ecx.std_path(&[sym::fmt, sym::Arguments, sym::new_v1]),
-            vec![lit_pieces, args],
-        )
-    }
-}
-
-fn may_contain_yield_point(e: &ast::Expr) -> bool {
-    struct MayContainYieldPoint(bool);
-
-    impl Visitor<'_> for MayContainYieldPoint {
-        fn visit_expr(&mut self, e: &ast::Expr) {
-            if let ast::ExprKind::Await(_) | ast::ExprKind::Yield(_) = e.kind {
-                self.0 = true;
-            } else {
-                visit::walk_expr(self, e);
-            }
-        }
-
-        fn visit_mac_call(&mut self, _: &ast::MacCall) {
-            self.0 = true;
-        }
-
-        fn visit_attribute(&mut self, _: &ast::Attribute) {
-            // Conservatively assume this may be a proc macro attribute in
-            // expression position.
-            self.0 = true;
-        }
-
-        fn visit_item(&mut self, _: &ast::Item) {
-            // Do not recurse into nested items.
-        }
-    }
-
-    let mut visitor = MayContainYieldPoint(false);
-    visitor.visit_expr(e);
-    visitor.0
-}
index d627c2ee09c4ef7555f820cc2a239b73c3133269..7886cae42a15ab1902d7d79ce677e8c4dd0be075 100644 (file)
@@ -1,13 +1,11 @@
 task:
   name: freebsd
   freebsd_instance:
-    image: freebsd-12-1-release-amd64
+    image: freebsd-13-1-release-amd64
   setup_rust_script:
     - pkg install -y curl git bash
     - curl https://sh.rustup.rs -sSf --output rustup.sh
     - sh rustup.sh --default-toolchain none -y --profile=minimal
-  cargo_bin_cache:
-    folder: ~/.cargo/bin
   target_cache:
     folder: target
   prepare_script:
@@ -15,9 +13,4 @@ task:
     - ./y.rs prepare
   test_script:
     - . $HOME/.cargo/env
-    - # Enable backtraces for easier debugging
-    - export RUST_BACKTRACE=1
-    - # Reduce amount of benchmark runs as they are slow
-    - export COMPILE_RUNS=2
-    - export RUN_RUNS=2
     - ./y.rs test
index a6bb12a66a247d66441c390105655e9ff0910978..c0daf69e98e912560c68b378f5c36bac6cf3004d 100644 (file)
@@ -25,6 +25,10 @@ jobs:
     runs-on: ${{ matrix.os }}
     timeout-minutes: 60
 
+    defaults:
+      run:
+        shell: bash
+
     strategy:
       fail-fast: false
       matrix:
@@ -46,36 +50,31 @@ jobs:
           - os: ubuntu-latest
             env:
               TARGET_TRIPLE: s390x-unknown-linux-gnu
+          - os: windows-latest
+            env:
+              TARGET_TRIPLE: x86_64-pc-windows-msvc
+          - os: windows-latest
+            env:
+              TARGET_TRIPLE: x86_64-pc-windows-gnu
 
     steps:
     - uses: actions/checkout@v3
 
-    - name: Cache cargo installed crates
-      uses: actions/cache@v3
-      with:
-        path: ~/.cargo/bin
-        key: ${{ runner.os }}-cargo-installed-crates
-
-    - name: Cache cargo registry and index
-      uses: actions/cache@v3
-      with:
-        path: |
-            ~/.cargo/registry
-            ~/.cargo/git
-        key: ${{ runner.os }}-cargo-registry-and-index-${{ hashFiles('**/Cargo.lock') }}
-
     - name: Cache cargo target dir
       uses: actions/cache@v3
       with:
         path: build/cg_clif
-        key: ${{ runner.os }}-cargo-build-target-${{ hashFiles('rust-toolchain', '**/Cargo.lock') }}
+        key: ${{ runner.os }}-${{ matrix.env.TARGET_TRIPLE }}-cargo-build-target-${{ hashFiles('rust-toolchain', '**/Cargo.lock') }}
+
+    - name: Set MinGW as the default toolchain
+      if: matrix.os == 'windows-latest' && matrix.env.TARGET_TRIPLE == 'x86_64-pc-windows-gnu'
+      run: rustup set default-host x86_64-pc-windows-gnu
 
     - name: Install MinGW toolchain and wine
       if: matrix.os == 'ubuntu-latest' && matrix.env.TARGET_TRIPLE == 'x86_64-pc-windows-gnu'
       run: |
         sudo apt-get update
         sudo apt-get install -y gcc-mingw-w64-x86-64 wine-stable
-        rustup target add x86_64-pc-windows-gnu
 
     - name: Install AArch64 toolchain and qemu
       if: matrix.os == 'ubuntu-latest' && matrix.env.TARGET_TRIPLE == 'aarch64-unknown-linux-gnu'
@@ -89,6 +88,13 @@ jobs:
         sudo apt-get update
         sudo apt-get install -y gcc-s390x-linux-gnu qemu-user
 
+    - name: Use sparse cargo registry
+      run: |
+        cat >> ~/.cargo/config.toml <<EOF
+        [unstable]
+        sparse-registry = true
+        EOF
+
     - name: Prepare dependencies
       run: ./y.rs prepare
 
@@ -104,49 +110,47 @@ jobs:
     - name: Test
       env:
         TARGET_TRIPLE: ${{ matrix.env.TARGET_TRIPLE }}
-      run: |
-        # Enable backtraces for easier debugging
-        export RUST_BACKTRACE=1
-
-        # Reduce amount of benchmark runs as they are slow
-        export COMPILE_RUNS=2
-        export RUN_RUNS=2
-
-        # Enable extra checks
-        export CG_CLIF_ENABLE_VERIFIER=1
-
-        ./y.rs test
+      run: ./y.rs test
 
     - name: Package prebuilt cg_clif
       run: tar cvfJ cg_clif.tar.xz dist
 
     - name: Upload prebuilt cg_clif
-      if: matrix.env.TARGET_TRIPLE != 'x86_64-pc-windows-gnu'
-      uses: actions/upload-artifact@v2
+      if: matrix.os == 'windows-latest' || matrix.env.TARGET_TRIPLE != 'x86_64-pc-windows-gnu'
+      uses: actions/upload-artifact@v3
       with:
         name: cg_clif-${{ matrix.env.TARGET_TRIPLE }}
         path: cg_clif.tar.xz
 
     - name: Upload prebuilt cg_clif (cross compile)
-      if: matrix.env.TARGET_TRIPLE == 'x86_64-pc-windows-gnu'
+      if: matrix.os != 'windows-latest' && matrix.env.TARGET_TRIPLE == 'x86_64-pc-windows-gnu'
       uses: actions/upload-artifact@v3
       with:
         name: cg_clif-${{ runner.os }}-cross-x86_64-mingw
         path: cg_clif.tar.xz
 
-  windows:
+
+  abi_cafe:
     runs-on: ${{ matrix.os }}
     timeout-minutes: 60
 
+    defaults:
+      run:
+        shell: bash
+
     strategy:
-      fail-fast: false
+      fail-fast: true
       matrix:
         include:
-          # Native Windows build with MSVC
+          - os: ubuntu-latest
+            env:
+              TARGET_TRIPLE: x86_64-unknown-linux-gnu
+          - os: macos-latest
+            env:
+              TARGET_TRIPLE: x86_64-apple-darwin
           - os: windows-latest
             env:
               TARGET_TRIPLE: x86_64-pc-windows-msvc
-          # cross-compile from Windows to Windows MinGW
           - os: windows-latest
             env:
               TARGET_TRIPLE: x86_64-pc-windows-gnu
@@ -154,20 +158,6 @@ jobs:
     steps:
     - uses: actions/checkout@v3
 
-    - name: Cache cargo installed crates
-      uses: actions/cache@v3
-      with:
-        path: ~/.cargo/bin
-        key: ${{ runner.os }}-${{ matrix.env.TARGET_TRIPLE }}-cargo-installed-crates
-
-    - name: Cache cargo registry and index
-      uses: actions/cache@v3
-      with:
-        path: |
-            ~/.cargo/registry
-            ~/.cargo/git
-        key: ${{ runner.os }}-${{ matrix.env.TARGET_TRIPLE }}-cargo-registry-and-index-${{ hashFiles('**/Cargo.lock') }}
-
     - name: Cache cargo target dir
       uses: actions/cache@v3
       with:
@@ -178,50 +168,20 @@ jobs:
       if: matrix.env.TARGET_TRIPLE == 'x86_64-pc-windows-gnu'
       run: rustup set default-host x86_64-pc-windows-gnu
 
-    - name: Prepare dependencies
+    - name: Use sparse cargo registry
       run: |
-        git config --global core.autocrlf false
-        rustc y.rs -o y.exe -g
-        ./y.exe prepare
+        cat >> ~/.cargo/config.toml <<EOF
+        [unstable]
+        sparse-registry = true
+        EOF
 
-    - name: Build without unstable features
-      env:
-        TARGET_TRIPLE: ${{ matrix.env.TARGET_TRIPLE }}
-      # This is the config rust-lang/rust uses for builds
-      run: ./y.rs build --no-unstable-features
+    - name: Prepare dependencies
+      run: ./y.rs prepare
 
     - name: Build
       run: ./y.rs build --sysroot none
 
-    - name: Test
-      run: |
-        # Enable backtraces for easier debugging
-        $Env:RUST_BACKTRACE=1
-
-        # Reduce amount of benchmark runs as they are slow
-        $Env:COMPILE_RUNS=2
-        $Env:RUN_RUNS=2
-
-        # Enable extra checks
-        $Env:CG_CLIF_ENABLE_VERIFIER=1
-
-        # WIP Disable some tests
-
-        # This fails due to some weird argument handling by hyperfine, not an actual regression
-        # more of a build system issue
-        (Get-Content config.txt) -replace '(bench.simple-raytracer)', '# $1' |  Out-File config.txt
-
-        # This fails with a different output than expected
-        (Get-Content config.txt) -replace '(test.regex-shootout-regex-dna)', '# $1' |  Out-File config.txt
-
-        ./y.exe test
-
-    - name: Package prebuilt cg_clif
-      # don't use compression as xzip isn't supported by tar on windows and bzip2 hangs
-      run: tar cvf cg_clif.tar dist
-
-    - name: Upload prebuilt cg_clif
-      uses: actions/upload-artifact@v3
-      with:
-        name: cg_clif-${{ matrix.env.TARGET_TRIPLE }}
-        path: cg_clif.tar
+    - name: Test abi-cafe
+      env:
+        TARGET_TRIPLE: ${{ matrix.env.TARGET_TRIPLE }}
+      run: ./y.rs abi-cafe
diff --git a/compiler/rustc_codegen_cranelift/.github/workflows/nightly-cranelift.yml b/compiler/rustc_codegen_cranelift/.github/workflows/nightly-cranelift.yml
deleted file mode 100644 (file)
index d0d58d2..0000000
+++ /dev/null
@@ -1,59 +0,0 @@
-name: Test nightly Cranelift
-
-on:
-  push:
-  schedule:
-    - cron: '17 1 * * *' # At 01:17 UTC every day.
-
-jobs:
-  build:
-    runs-on: ubuntu-latest
-    timeout-minutes: 60
-
-    steps:
-    - uses: actions/checkout@v3
-
-    - name: Cache cargo installed crates
-      uses: actions/cache@v3
-      with:
-        path: ~/.cargo/bin
-        key: ubuntu-latest-cargo-installed-crates
-
-    - name: Prepare dependencies
-      run: |
-        git config --global user.email "user@example.com"
-        git config --global user.name "User"
-        ./y.rs prepare
-
-    - name: Patch Cranelift
-      run: |
-        sed -i 's/cranelift-codegen = { version = "\w*.\w*.\w*", features = \["unwind", "all-arch"\] }/cranelift-codegen = { git = "https:\/\/github.com\/bytecodealliance\/wasmtime.git", features = ["unwind", "all-arch"] }/' Cargo.toml
-        sed -i 's/cranelift-frontend = "\w*.\w*.\w*"/cranelift-frontend = { git = "https:\/\/github.com\/bytecodealliance\/wasmtime.git" }/' Cargo.toml
-        sed -i 's/cranelift-module = "\w*.\w*.\w*"/cranelift-module = { git = "https:\/\/github.com\/bytecodealliance\/wasmtime.git" }/' Cargo.toml
-        sed -i 's/cranelift-native = "\w*.\w*.\w*"/cranelift-native = { git = "https:\/\/github.com\/bytecodealliance\/wasmtime.git" }/' Cargo.toml
-        sed -i 's/cranelift-jit = { version = "\w*.\w*.\w*", optional = true }/cranelift-jit = { git = "https:\/\/github.com\/bytecodealliance\/wasmtime.git", optional = true }/' Cargo.toml
-        sed -i 's/cranelift-object = "\w*.\w*.\w*"/cranelift-object = { git = "https:\/\/github.com\/bytecodealliance\/wasmtime.git" }/' Cargo.toml
-
-        sed -i 's/object = { version = "0.27.0"/object = { version = "0.28.0"/' Cargo.toml
-
-        cat Cargo.toml
-
-    - name: Build without unstable features
-      # This is the config rust-lang/rust uses for builds
-      run: ./y.rs build --no-unstable-features
-
-    - name: Build
-      run: ./y.rs build --sysroot none
-    - name: Test
-      run: |
-        # Enable backtraces for easier debugging
-        export RUST_BACKTRACE=1
-
-        # Reduce amount of benchmark runs as they are slow
-        export COMPILE_RUNS=2
-        export RUN_RUNS=2
-
-        # Enable extra checks
-        export CG_CLIF_ENABLE_VERIFIER=1
-
-        ./test.sh
index bef806318efa836aeeb8d6df06d880b77be677fb..5faa8f0540451b848506fadd139fc6333429b230 100644 (file)
@@ -10,73 +10,45 @@ jobs:
     steps:
     - uses: actions/checkout@v3
 
-    - name: Cache cargo installed crates
-      uses: actions/cache@v3
-      with:
-        path: ~/.cargo/bin
-        key: ${{ runner.os }}-cargo-installed-crates
-
-    - name: Cache cargo registry and index
-      uses: actions/cache@v3
-      with:
-        path: |
-            ~/.cargo/registry
-            ~/.cargo/git
-        key: ${{ runner.os }}-cargo-registry-and-index-${{ hashFiles('**/Cargo.lock') }}
-
     - name: Cache cargo target dir
       uses: actions/cache@v3
       with:
         path: build/cg_clif
         key: ${{ runner.os }}-cargo-build-target-${{ hashFiles('rust-toolchain', '**/Cargo.lock') }}
 
-    - name: Prepare dependencies
+    - name: Use sparse cargo registry
       run: |
-        git config --global user.email "user@example.com"
-        git config --global user.name "User"
-        ./y.rs prepare
+        cat >> ~/.cargo/config.toml <<EOF
+        [unstable]
+        sparse-registry = true
+        EOF
 
-    - name: Test
-      run: |
-        # Enable backtraces for easier debugging
-        export RUST_BACKTRACE=1
+    - name: Prepare dependencies
+      run: ./y.rs prepare
 
-        ./scripts/test_bootstrap.sh
+    - name: Test
+      run: ./scripts/test_bootstrap.sh
   rustc_test_suite:
     runs-on: ubuntu-latest
 
     steps:
     - uses: actions/checkout@v3
 
-    - name: Cache cargo installed crates
-      uses: actions/cache@v3
-      with:
-        path: ~/.cargo/bin
-        key: ${{ runner.os }}-cargo-installed-crates
-
-    - name: Cache cargo registry and index
-      uses: actions/cache@v3
-      with:
-        path: |
-            ~/.cargo/registry
-            ~/.cargo/git
-        key: ${{ runner.os }}-cargo-registry-and-index-${{ hashFiles('**/Cargo.lock') }}
-
     - name: Cache cargo target dir
       uses: actions/cache@v3
       with:
         path: build/cg_clif
         key: ${{ runner.os }}-cargo-build-target-${{ hashFiles('rust-toolchain', '**/Cargo.lock') }}
 
-    - name: Prepare dependencies
+    - name: Use sparse cargo registry
       run: |
-        git config --global user.email "user@example.com"
-        git config --global user.name "User"
-        ./y.rs prepare
+        cat >> ~/.cargo/config.toml <<EOF
+        [unstable]
+        sparse-registry = true
+        EOF
 
-    - name: Test
-      run: |
-        # Enable backtraces for easier debugging
-        export RUST_BACKTRACE=1
+    - name: Prepare dependencies
+      run: ./y.rs prepare
 
-        ./scripts/test_rustc_tests.sh
+    - name: Test
+      run: ./scripts/test_rustc_tests.sh
index b443fd58a1b98344bec2720e26139b6467907d89..8012e93f6a90ebdee2747548145a52b8f2e3f45c 100644 (file)
@@ -1,4 +1,4 @@
-target
+/target
 **/*.rs.bk
 *.rlib
 *.o
@@ -11,9 +11,6 @@ perf.data.old
 /y.exe
 /y.pdb
 /build
-/build_sysroot/sysroot_src
-/build_sysroot/compiler-builtins
-/build_sysroot/rustc_version
 /dist
 /rust
 /download
index bc914e37d2b51dda8d3a0e4ef090a4cc1399fc90..7c8703cba505c6e221910aabcef2a5ea4f712a41 100644 (file)
@@ -1,4 +1,6 @@
 {
+    "editor.formatOnSave": true,
+
     // source for rustc_* is not included in the rust-src component; disable the errors about this
     "rust-analyzer.diagnostics.disabled": ["unresolved-extern-crate", "unresolved-macro-call"],
     "rust-analyzer.imports.granularity.enforce": true,
@@ -30,7 +32,7 @@
             ]
         },
         {
-            "sysroot_src": "./build_sysroot/sysroot_src/library",
+            "sysroot_src": "./download/sysroot/sysroot_src/library",
             "crates": [
                 {
                     "root_module": "./example/std_example.rs",
index e4d3e9ca5ae0a8676863063216c420232248a554..50249ea1bdb493e08815b1f81c373c4a1d4937db 100644 (file)
@@ -57,28 +57,28 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
 
 [[package]]
 name = "cranelift-bforest"
-version = "0.90.1"
+version = "0.92.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b62c772976416112fa4484cbd688cb6fb35fd430005c1c586224fc014018abad"
+checksum = "2f3d54eab028f5805ae3b26fd60eca3f3a9cfb76b989d9bab173be3f61356cc3"
 dependencies = [
  "cranelift-entity",
 ]
 
 [[package]]
 name = "cranelift-codegen"
-version = "0.90.1"
+version = "0.92.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9b40ed2dd13c2ac7e24f88a3090c68ad3414eb1d066a95f8f1f7b3b819cb4e46"
+checksum = "2be1d5f2c3cca1efb691844bc1988b89c77291f13f778499a3f3c0cf49c0ed61"
 dependencies = [
  "arrayvec",
  "bumpalo",
  "cranelift-bforest",
  "cranelift-codegen-meta",
  "cranelift-codegen-shared",
- "cranelift-egraph",
  "cranelift-entity",
  "cranelift-isle",
  "gimli",
+ "hashbrown",
  "log",
  "regalloc2",
  "smallvec",
@@ -87,44 +87,30 @@ dependencies = [
 
 [[package]]
 name = "cranelift-codegen-meta"
-version = "0.90.1"
+version = "0.92.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bb927a8f1c27c34ee3759b6b0ffa528d2330405d5cc4511f0cab33fe2279f4b5"
+checksum = "3f9b1b1089750ce4005893af7ee00bb08a2cf1c9779999c0f7164cbc8ad2e0d2"
 dependencies = [
  "cranelift-codegen-shared",
 ]
 
 [[package]]
 name = "cranelift-codegen-shared"
-version = "0.90.1"
+version = "0.92.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "43dfa417b884a9ab488d95fd6b93b25e959321fe7bfd7a0a960ba5d7fb7ab927"
-
-[[package]]
-name = "cranelift-egraph"
-version = "0.90.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e0a66b39785efd8513d2cca967ede56d6cc57c8d7986a595c7c47d0c78de8dce"
-dependencies = [
- "cranelift-entity",
- "fxhash",
- "hashbrown",
- "indexmap",
- "log",
- "smallvec",
-]
+checksum = "cc5fbaec51de47297fd7304986fd53c8c0030abbe69728a60d72e1c63559318d"
 
 [[package]]
 name = "cranelift-entity"
-version = "0.90.1"
+version = "0.92.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0637ffde963cb5d759bc4d454cfa364b6509e6c74cdaa21298add0ed9276f346"
+checksum = "dab984c94593f876090fae92e984bdcc74d9b1acf740ab5f79036001c65cba13"
 
 [[package]]
 name = "cranelift-frontend"
-version = "0.90.1"
+version = "0.92.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fb72b8342685e850cb037350418f62cc4fc55d6c2eb9c7ca01b82f9f1a6f3d56"
+checksum = "6e0cb3102d21a2fe5f3210af608748ddd0cd09825ac12d42dc56ed5ed8725fe0"
 dependencies = [
  "cranelift-codegen",
  "log",
@@ -134,15 +120,15 @@ dependencies = [
 
 [[package]]
 name = "cranelift-isle"
-version = "0.90.1"
+version = "0.92.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "850579cb9e4b448f7c301f1e6e6cbad99abe3f1f1d878a4994cb66e33c6db8cd"
+checksum = "72101dd1f441d629735143c41e00b3428f9267738176983ef588ff43382af0a0"
 
 [[package]]
 name = "cranelift-jit"
-version = "0.90.1"
+version = "0.92.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9add822ad66dcbe152b5ab57de10240a2df4505099f2f6c27159acb711890bd4"
+checksum = "6557f8ce44d498777f2495aa58d9692a4a37d6f84aa445750d666cef770b6a5c"
 dependencies = [
  "anyhow",
  "cranelift-codegen",
@@ -159,9 +145,9 @@ dependencies = [
 
 [[package]]
 name = "cranelift-module"
-version = "0.90.1"
+version = "0.92.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "406b772626fc2664864cf947f3895a23b619895c7fff635f3622e2d857f4492f"
+checksum = "88807e1c0c47ec02fe433333ccbe56b480425418b1470e333205e11650697d72"
 dependencies = [
  "anyhow",
  "cranelift-codegen",
@@ -169,9 +155,9 @@ dependencies = [
 
 [[package]]
 name = "cranelift-native"
-version = "0.90.1"
+version = "0.92.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2d0a279e5bcba3e0466c734d8d8eb6bfc1ad29e95c37f3e4955b492b5616335e"
+checksum = "c22b0d9fcbe3fc5a1af9e7021b44ce42b930bcefac446ce22e02e8f9a0d67120"
 dependencies = [
  "cranelift-codegen",
  "libc",
@@ -180,9 +166,9 @@ dependencies = [
 
 [[package]]
 name = "cranelift-object"
-version = "0.90.1"
+version = "0.92.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "39793c550f0c1d7db96c2fc1324583670c8143befe6edbfbaf1c68aba53be983"
+checksum = "341375758d7c3fedc0b5315f552e6f0feac46baf87c450a15e9455ef47c2b261"
 dependencies = [
  "anyhow",
  "cranelift-codegen",
@@ -317,9 +303,9 @@ checksum = "86f0b0d4bf799edbc74508c1e8bf170ff5f41238e5f8225603ca7caaae2b7860"
 
 [[package]]
 name = "regalloc2"
-version = "0.4.2"
+version = "0.5.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "91b2eab54204ea0117fe9a060537e0b07a4e72f7c7d182361ecc346cab2240e5"
+checksum = "300d4fbfb40c1c66a78ba3ddd41c1110247cf52f97b87d0f2fc9209bd49b030c"
 dependencies = [
  "fxhash",
  "log",
@@ -347,7 +333,6 @@ dependencies = [
  "cranelift-frontend",
  "cranelift-jit",
  "cranelift-module",
- "cranelift-native",
  "cranelift-object",
  "gimli",
  "indexmap",
@@ -396,9 +381,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
 
 [[package]]
 name = "wasmtime-jit-icache-coherence"
-version = "2.0.1"
+version = "5.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e6bbabb309c06cc238ee91b1455b748c45f0bdcab0dda2c2db85b0a1e69fcb66"
+checksum = "08fcba5ebd96da2a9f0747ab6337fe9788adfb3f63fa2c180520d665562d257e"
 dependencies = [
  "cfg-if",
  "libc",
@@ -429,43 +414,57 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
 
 [[package]]
 name = "windows-sys"
-version = "0.36.1"
+version = "0.42.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ea04155a16a59f9eab786fe12a4a450e75cdb175f9e0d80da1e17db09f55b8d2"
+checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7"
 dependencies = [
+ "windows_aarch64_gnullvm",
  "windows_aarch64_msvc",
  "windows_i686_gnu",
  "windows_i686_msvc",
  "windows_x86_64_gnu",
+ "windows_x86_64_gnullvm",
  "windows_x86_64_msvc",
 ]
 
+[[package]]
+name = "windows_aarch64_gnullvm"
+version = "0.42.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "41d2aa71f6f0cbe00ae5167d90ef3cfe66527d6f613ca78ac8024c3ccab9a19e"
+
 [[package]]
 name = "windows_aarch64_msvc"
-version = "0.36.1"
+version = "0.42.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9bb8c3fd39ade2d67e9874ac4f3db21f0d710bee00fe7cab16949ec184eeaa47"
+checksum = "dd0f252f5a35cac83d6311b2e795981f5ee6e67eb1f9a7f64eb4500fbc4dcdb4"
 
 [[package]]
 name = "windows_i686_gnu"
-version = "0.36.1"
+version = "0.42.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "180e6ccf01daf4c426b846dfc66db1fc518f074baa793aa7d9b9aaeffad6a3b6"
+checksum = "fbeae19f6716841636c28d695375df17562ca208b2b7d0dc47635a50ae6c5de7"
 
 [[package]]
 name = "windows_i686_msvc"
-version = "0.36.1"
+version = "0.42.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e2e7917148b2812d1eeafaeb22a97e4813dfa60a3f8f78ebe204bcc88f12f024"
+checksum = "84c12f65daa39dd2babe6e442988fc329d6243fdce47d7d2d155b8d874862246"
 
 [[package]]
 name = "windows_x86_64_gnu"
-version = "0.36.1"
+version = "0.42.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bf7b1b21b5362cbc318f686150e5bcea75ecedc74dd157d874d754a2ca44b0ed"
+
+[[package]]
+name = "windows_x86_64_gnullvm"
+version = "0.42.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4dcd171b8776c41b97521e5da127a2d86ad280114807d0b2ab1e462bc764d9e1"
+checksum = "09d525d2ba30eeb3297665bd434a54297e4170c7f1a44cad4ef58095b4cd2028"
 
 [[package]]
 name = "windows_x86_64_msvc"
-version = "0.36.1"
+version = "0.42.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680"
+checksum = "f40009d85759725a34da6d89a94e63d7bdc50a862acf0dbc7c8e488f1edcb6f5"
index 2b216ca072f0096832412085a0eae3fda4dc79ff..34117c2886febae43ecebb4f93cc498b2555ed58 100644 (file)
@@ -15,12 +15,14 @@ crate-type = ["dylib"]
 
 [dependencies]
 # These have to be in sync with each other
-cranelift-codegen = { version = "0.90.1", features = ["unwind", "all-arch"] }
-cranelift-frontend = "0.90.1"
-cranelift-module = "0.90.1"
-cranelift-native = "0.90.1"
-cranelift-jit = { version = "0.90.1", optional = true }
-cranelift-object = "0.90.1"
+cranelift-codegen = { version = "0.92", features = ["unwind", "all-arch"] }
+cranelift-frontend = { version = "0.92" }
+cranelift-module = { version = "0.92" }
+# NOTE vendored as src/cranelift_native.rs
+# FIXME revert back to the external crate with Cranelift 0.93
+#cranelift-native = { version = "0.92" }
+cranelift-jit = { version = "0.92", optional = true }
+cranelift-object = { version = "0.92" }
 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"] }
index 0e9c77244d4cc85d765371e97370db5c0adebf11..b87a9dc51e8d0f3f956e5fc69acb701a2c8e1ad3 100644 (file)
@@ -8,9 +8,9 @@ If not please open an issue.
 ## Building and testing
 
 ```bash
-$ git clone https://github.com/bjorn3/rustc_codegen_cranelift.git
+$ git clone https://github.com/bjorn3/rustc_codegen_cranelift
 $ cd rustc_codegen_cranelift
-$ ./y.rs prepare # download and patch sysroot src and install hyperfine for benchmarking
+$ ./y.rs prepare
 $ ./y.rs build
 ```
 
@@ -20,13 +20,12 @@ To run the test suite replace the last command with:
 $ ./test.sh
 ```
 
-This will implicitly build cg_clif too. Both `y.rs build` and `test.sh` accept a `--debug` argument to
-build in debug mode.
+For more docs on how to build and test see [build_system/usage.txt](build_system/usage.txt) or the help message of `./y.rs`.
 
-Alternatively you can download a pre built version from [GHA]. It is listed in the artifacts section
+Alternatively you can download a pre built version from [Github Actions]. It is listed in the artifacts section
 of workflow runs. Unfortunately due to GHA restrictions you need to be logged in to access it.
 
-[GHA]: https://github.com/bjorn3/rustc_codegen_cranelift/actions?query=branch%3Amaster+event%3Apush+is%3Asuccess
+[Github Actions]: https://github.com/bjorn3/rustc_codegen_cranelift/actions?query=branch%3Amaster+event%3Apush+is%3Asuccess
 
 ## Usage
 
@@ -53,7 +52,8 @@ configuration options.
 
 * Inline assembly ([no cranelift support](https://github.com/bytecodealliance/wasmtime/issues/1041))
     * On UNIX there is support for invoking an external assembler for `global_asm!` and `asm!`.
-* SIMD ([tracked here](https://github.com/bjorn3/rustc_codegen_cranelift/issues/171), some basic things work)
+* SIMD ([tracked here](https://github.com/bjorn3/rustc_codegen_cranelift/issues/171), `std::simd` fully works, `std::arch` is partially supported)
+* Unwinding on panics ([no cranelift support](https://github.com/bytecodealliance/wasmtime/issues/1677), `-Cpanic=abort` is enabled by default)
 
 ## License
 
index bba3210536ef7832e44ba9dbb5e46c3ee036baf6..24f15fc8521fee0dba322e556e6cbe49d3782238 100644 (file)
@@ -34,9 +34,9 @@ dependencies = [
 
 [[package]]
 name = "cc"
-version = "1.0.77"
+version = "1.0.78"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e9f73505338f7d905b19d18738976aae232eb46b8efc15554ffc56deb5d9ebe4"
+checksum = "a20104e2335ce8a659d6dd92a51a767a0c062599c73b343fd152cb401e828c3d"
 
 [[package]]
 name = "cfg-if"
@@ -50,9 +50,9 @@ dependencies = [
 
 [[package]]
 name = "compiler_builtins"
-version = "0.1.85"
+version = "0.1.86"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "13e81c6cd7ab79f51a0c927d22858d61ad12bd0b3865f0b13ece02a4486aeabb"
+checksum = "5dae98c88e576098d7ab13ebcb40cc43e5114b2beafe61a87cda9200649ff205"
 dependencies = [
  "rustc-std-workspace-core",
 ]
@@ -129,9 +129,9 @@ dependencies = [
 
 [[package]]
 name = "libc"
-version = "0.2.138"
+version = "0.2.139"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "db6d7e329c562c5dfab7a46a2afabc8b987ab9a4834c9d1ca04dc54c1546cef8"
+checksum = "201de327520df007757c1f0adce6e827fe8562fbc28bfd9c15571c66ca1f5f79"
 dependencies = [
  "rustc-std-workspace-core",
 ]
index a081fdaa1c7e6475a727f764c033f07090b2b87e..dbee9be04eea6356920bbcde1c97583abb0c9cb7 100644 (file)
@@ -1,7 +1,6 @@
 use std::path::Path;
 
 use super::build_sysroot;
-use super::config;
 use super::path::Dirs;
 use super::prepare::GitRepo;
 use super::utils::{spawn_and_wait, CargoProject, Compiler};
 pub(crate) static ABI_CAFE_REPO: GitRepo =
     GitRepo::github("Gankra", "abi-cafe", "4c6dc8c9c687e2b3a760ff2176ce236872b37212", "abi-cafe");
 
-static ABI_CAFE: CargoProject = CargoProject::new(&ABI_CAFE_REPO.source_dir(), "abi_cafe");
+pub(crate) static ABI_CAFE: CargoProject =
+    CargoProject::new(&ABI_CAFE_REPO.source_dir(), "abi_cafe");
 
 pub(crate) fn run(
     channel: &str,
     sysroot_kind: SysrootKind,
     dirs: &Dirs,
     cg_clif_dylib: &Path,
-    host_triple: &str,
-    target_triple: &str,
+    bootstrap_host_compiler: &Compiler,
 ) {
-    if !config::get_bool("testsuite.abi-cafe") {
-        eprintln!("[SKIP] abi-cafe");
-        return;
-    }
-
-    if host_triple != target_triple {
-        eprintln!("[SKIP] abi-cafe (cross-compilation not supported)");
-        return;
-    }
-
     eprintln!("Building sysroot for abi-cafe");
     build_sysroot::build_sysroot(
         dirs,
         channel,
         sysroot_kind,
         cg_clif_dylib,
-        host_triple,
-        target_triple,
+        bootstrap_host_compiler,
+        bootstrap_host_compiler.triple.clone(),
     );
 
     eprintln!("Running abi-cafe");
 
     let pairs = ["rustc_calls_cgclif", "cgclif_calls_rustc", "cgclif_calls_cc", "cc_calls_cgclif"];
 
-    let mut cmd = ABI_CAFE.run(&Compiler::host(), dirs);
+    let mut cmd = ABI_CAFE.run(bootstrap_host_compiler, dirs);
     cmd.arg("--");
     cmd.arg("--pairs");
     cmd.args(pairs);
diff --git a/compiler/rustc_codegen_cranelift/build_system/bench.rs b/compiler/rustc_codegen_cranelift/build_system/bench.rs
new file mode 100644 (file)
index 0000000..01d44da
--- /dev/null
@@ -0,0 +1,97 @@
+use std::env;
+use std::fs;
+use std::path::Path;
+
+use super::path::{Dirs, RelPath};
+use super::prepare::GitRepo;
+use super::rustc_info::get_file_name;
+use super::utils::{hyperfine_command, is_ci, spawn_and_wait, CargoProject, Compiler};
+
+pub(crate) static SIMPLE_RAYTRACER_REPO: GitRepo = GitRepo::github(
+    "ebobby",
+    "simple-raytracer",
+    "804a7a21b9e673a482797aa289a18ed480e4d813",
+    "<none>",
+);
+
+// Use a separate target dir for the initial LLVM build to reduce unnecessary recompiles
+pub(crate) static SIMPLE_RAYTRACER_LLVM: CargoProject =
+    CargoProject::new(&SIMPLE_RAYTRACER_REPO.source_dir(), "simple_raytracer_llvm");
+
+pub(crate) static SIMPLE_RAYTRACER: CargoProject =
+    CargoProject::new(&SIMPLE_RAYTRACER_REPO.source_dir(), "simple_raytracer");
+
+pub(crate) fn benchmark(dirs: &Dirs, bootstrap_host_compiler: &Compiler) {
+    benchmark_simple_raytracer(dirs, bootstrap_host_compiler);
+}
+
+fn benchmark_simple_raytracer(dirs: &Dirs, bootstrap_host_compiler: &Compiler) {
+    if std::process::Command::new("hyperfine").output().is_err() {
+        eprintln!("Hyperfine not installed");
+        eprintln!("Hint: Try `cargo install hyperfine` to install hyperfine");
+        std::process::exit(1);
+    }
+
+    eprintln!("[LLVM BUILD] simple-raytracer");
+    let build_cmd = SIMPLE_RAYTRACER_LLVM.build(bootstrap_host_compiler, dirs);
+    spawn_and_wait(build_cmd);
+    fs::copy(
+        SIMPLE_RAYTRACER_LLVM
+            .target_dir(dirs)
+            .join(&bootstrap_host_compiler.triple)
+            .join("debug")
+            .join(get_file_name("main", "bin")),
+        RelPath::BUILD.to_path(dirs).join(get_file_name("raytracer_cg_llvm", "bin")),
+    )
+    .unwrap();
+
+    let run_runs = env::var("RUN_RUNS")
+        .unwrap_or(if is_ci() { "2" } else { "10" }.to_string())
+        .parse()
+        .unwrap();
+
+    eprintln!("[BENCH COMPILE] ebobby/simple-raytracer");
+    let cargo_clif =
+        RelPath::DIST.to_path(dirs).join(get_file_name("cargo_clif", "bin").replace('_', "-"));
+    let manifest_path = SIMPLE_RAYTRACER.manifest_path(dirs);
+    let target_dir = SIMPLE_RAYTRACER.target_dir(dirs);
+
+    let clean_cmd = format!(
+        "cargo clean --manifest-path {manifest_path} --target-dir {target_dir}",
+        manifest_path = manifest_path.display(),
+        target_dir = target_dir.display(),
+    );
+    let llvm_build_cmd = format!(
+        "cargo build --manifest-path {manifest_path} --target-dir {target_dir}",
+        manifest_path = manifest_path.display(),
+        target_dir = target_dir.display(),
+    );
+    let clif_build_cmd = format!(
+        "{cargo_clif} build --manifest-path {manifest_path} --target-dir {target_dir}",
+        cargo_clif = cargo_clif.display(),
+        manifest_path = manifest_path.display(),
+        target_dir = target_dir.display(),
+    );
+
+    let bench_compile =
+        hyperfine_command(1, run_runs, Some(&clean_cmd), &llvm_build_cmd, &clif_build_cmd);
+
+    spawn_and_wait(bench_compile);
+
+    eprintln!("[BENCH RUN] ebobby/simple-raytracer");
+    fs::copy(
+        target_dir.join("debug").join(get_file_name("main", "bin")),
+        RelPath::BUILD.to_path(dirs).join(get_file_name("raytracer_cg_clif", "bin")),
+    )
+    .unwrap();
+
+    let mut bench_run = hyperfine_command(
+        0,
+        run_runs,
+        None,
+        Path::new(".").join(get_file_name("raytracer_cg_llvm", "bin")).to_str().unwrap(),
+        Path::new(".").join(get_file_name("raytracer_cg_clif", "bin")).to_str().unwrap(),
+    );
+    bench_run.current_dir(RelPath::BUILD.to_path(dirs));
+    spawn_and_wait(bench_run);
+}
index fde8ef424ccc5441e0198ef7b33b23c39dbe37bc..514404305a3fa0416635e45dc7ad0b9a6a34357a 100644 (file)
@@ -5,15 +5,15 @@
 use super::rustc_info::get_file_name;
 use super::utils::{is_ci, CargoProject, Compiler};
 
-static CG_CLIF: CargoProject = CargoProject::new(&RelPath::SOURCE, "cg_clif");
+pub(crate) static CG_CLIF: CargoProject = CargoProject::new(&RelPath::SOURCE, "cg_clif");
 
 pub(crate) fn build_backend(
     dirs: &Dirs,
     channel: &str,
-    host_triple: &str,
+    bootstrap_host_compiler: &Compiler,
     use_unstable_features: bool,
 ) -> PathBuf {
-    let mut cmd = CG_CLIF.build(&Compiler::host(), dirs);
+    let mut cmd = CG_CLIF.build(&bootstrap_host_compiler, dirs);
 
     cmd.env("CARGO_BUILD_INCREMENTAL", "true"); // Force incr comp even in release mode
 
@@ -25,6 +25,8 @@ pub(crate) fn build_backend(
 
         // Disabling incr comp reduces cache size and incr comp doesn't save as much on CI anyway
         cmd.env("CARGO_BUILD_INCREMENTAL", "false");
+
+        cmd.env("CARGO_PROFILE_RELEASE_DEBUG_ASSERTIONS", "true");
     }
 
     if use_unstable_features {
@@ -46,7 +48,7 @@ pub(crate) fn build_backend(
 
     CG_CLIF
         .target_dir(dirs)
-        .join(host_triple)
+        .join(&bootstrap_host_compiler.triple)
         .join(channel)
         .join(get_file_name("rustc_codegen_cranelift", "dylib"))
 }
index cbbf09b9b97b8422ab06caff3b59b34c6352dfd4..bd04fdbe304a3031cf7995133a306a04744ff118 100644 (file)
@@ -1,31 +1,32 @@
 use std::fs;
-use std::path::Path;
+use std::path::{Path, PathBuf};
 use std::process::{self, Command};
 
 use super::path::{Dirs, RelPath};
-use super::rustc_info::{get_file_name, get_rustc_version, get_wrapper_file_name};
-use super::utils::{spawn_and_wait, try_hard_link, CargoProject, Compiler};
+use super::rustc_info::{get_file_name, get_rustc_version, get_toolchain_name};
+use super::utils::{remove_dir_if_exists, spawn_and_wait, try_hard_link, CargoProject, Compiler};
 use super::SysrootKind;
 
 static DIST_DIR: RelPath = RelPath::DIST;
 static BIN_DIR: RelPath = RelPath::DIST.join("bin");
 static LIB_DIR: RelPath = RelPath::DIST.join("lib");
-static RUSTLIB_DIR: RelPath = LIB_DIR.join("rustlib");
 
 pub(crate) fn build_sysroot(
     dirs: &Dirs,
     channel: &str,
     sysroot_kind: SysrootKind,
     cg_clif_dylib_src: &Path,
-    host_triple: &str,
-    target_triple: &str,
-) {
+    bootstrap_host_compiler: &Compiler,
+    target_triple: String,
+) -> Compiler {
     eprintln!("[BUILD] sysroot {:?}", sysroot_kind);
 
     DIST_DIR.ensure_fresh(dirs);
     BIN_DIR.ensure_exists(dirs);
     LIB_DIR.ensure_exists(dirs);
 
+    let is_native = bootstrap_host_compiler.triple == target_triple;
+
     // Copy the backend
     let cg_clif_dylib_path = if cfg!(windows) {
         // Windows doesn't have rpath support, so the cg_clif dylib needs to be next to the
@@ -35,129 +36,169 @@ pub(crate) fn build_sysroot(
         LIB_DIR
     }
     .to_path(dirs)
-    .join(get_file_name("rustc_codegen_cranelift", "dylib"));
+    .join(cg_clif_dylib_src.file_name().unwrap());
     try_hard_link(cg_clif_dylib_src, &cg_clif_dylib_path);
 
     // Build and copy rustc and cargo wrappers
+    let wrapper_base_name = get_file_name("____", "bin");
+    let toolchain_name = get_toolchain_name();
     for wrapper in ["rustc-clif", "rustdoc-clif", "cargo-clif"] {
-        let wrapper_name = get_wrapper_file_name(wrapper, "bin");
+        let wrapper_name = wrapper_base_name.replace("____", wrapper);
 
-        let mut build_cargo_wrapper_cmd = Command::new("rustc");
+        let mut build_cargo_wrapper_cmd = Command::new(&bootstrap_host_compiler.rustc);
         build_cargo_wrapper_cmd
+            .env("TOOLCHAIN_NAME", toolchain_name.clone())
             .arg(RelPath::SCRIPTS.to_path(dirs).join(&format!("{wrapper}.rs")))
             .arg("-o")
             .arg(DIST_DIR.to_path(dirs).join(wrapper_name))
-            .arg("-g");
+            .arg("-Cstrip=debuginfo");
         spawn_and_wait(build_cargo_wrapper_cmd);
     }
 
-    let default_sysroot = super::rustc_info::get_default_sysroot();
+    let host = build_sysroot_for_triple(
+        dirs,
+        channel,
+        bootstrap_host_compiler.clone(),
+        &cg_clif_dylib_path,
+        sysroot_kind,
+    );
+    host.install_into_sysroot(&DIST_DIR.to_path(dirs));
 
-    let host_rustlib_lib = RUSTLIB_DIR.to_path(dirs).join(host_triple).join("lib");
-    let target_rustlib_lib = RUSTLIB_DIR.to_path(dirs).join(target_triple).join("lib");
-    fs::create_dir_all(&host_rustlib_lib).unwrap();
-    fs::create_dir_all(&target_rustlib_lib).unwrap();
+    if !is_native {
+        build_sysroot_for_triple(
+            dirs,
+            channel,
+            {
+                let mut bootstrap_target_compiler = bootstrap_host_compiler.clone();
+                bootstrap_target_compiler.triple = target_triple.clone();
+                bootstrap_target_compiler.set_cross_linker_and_runner();
+                bootstrap_target_compiler
+            },
+            &cg_clif_dylib_path,
+            sysroot_kind,
+        )
+        .install_into_sysroot(&DIST_DIR.to_path(dirs));
+    }
 
-    if target_triple == "x86_64-pc-windows-gnu" {
-        if !default_sysroot.join("lib").join("rustlib").join(target_triple).join("lib").exists() {
-            eprintln!(
-                "The x86_64-pc-windows-gnu target needs to be installed first before it is possible \
-                to compile a sysroot for it.",
-            );
-            process::exit(1);
+    // Copy std for the host to the lib dir. This is necessary for the jit mode to find
+    // libstd.
+    for lib in host.libs {
+        let filename = lib.file_name().unwrap().to_str().unwrap();
+        if filename.contains("std-") && !filename.contains(".rlib") {
+            try_hard_link(&lib, LIB_DIR.to_path(dirs).join(lib.file_name().unwrap()));
         }
-        for file in fs::read_dir(
-            default_sysroot.join("lib").join("rustlib").join(target_triple).join("lib"),
-        )
-        .unwrap()
-        {
-            let file = file.unwrap().path();
-            if file.extension().map_or(true, |ext| ext.to_str().unwrap() != "o") {
-                continue; // only copy object files
-            }
-            try_hard_link(&file, target_rustlib_lib.join(file.file_name().unwrap()));
+    }
+
+    let mut target_compiler = {
+        let dirs: &Dirs = &dirs;
+        let rustc_clif =
+            RelPath::DIST.to_path(&dirs).join(wrapper_base_name.replace("____", "rustc-clif"));
+        let rustdoc_clif =
+            RelPath::DIST.to_path(&dirs).join(wrapper_base_name.replace("____", "rustdoc-clif"));
+
+        Compiler {
+            cargo: bootstrap_host_compiler.cargo.clone(),
+            rustc: rustc_clif.clone(),
+            rustdoc: rustdoc_clif.clone(),
+            rustflags: String::new(),
+            rustdocflags: String::new(),
+            triple: target_triple,
+            runner: vec![],
         }
+    };
+    if !is_native {
+        target_compiler.set_cross_linker_and_runner();
     }
+    target_compiler
+}
 
-    match sysroot_kind {
-        SysrootKind::None => {} // Nothing to do
-        SysrootKind::Llvm => {
-            for file in fs::read_dir(
-                default_sysroot.join("lib").join("rustlib").join(host_triple).join("lib"),
-            )
-            .unwrap()
-            {
-                let file = file.unwrap().path();
-                let file_name_str = file.file_name().unwrap().to_str().unwrap();
-                if (file_name_str.contains("rustc_")
-                    && !file_name_str.contains("rustc_std_workspace_")
-                    && !file_name_str.contains("rustc_demangle"))
-                    || file_name_str.contains("chalk")
-                    || file_name_str.contains("tracing")
-                    || file_name_str.contains("regex")
-                {
-                    // These are large crates that are part of the rustc-dev component and are not
-                    // necessary to run regular programs.
-                    continue;
-                }
-                try_hard_link(&file, host_rustlib_lib.join(file.file_name().unwrap()));
-            }
+struct SysrootTarget {
+    triple: String,
+    libs: Vec<PathBuf>,
+}
 
-            if target_triple != host_triple {
-                for file in fs::read_dir(
-                    default_sysroot.join("lib").join("rustlib").join(target_triple).join("lib"),
-                )
-                .unwrap()
-                {
-                    let file = file.unwrap().path();
-                    try_hard_link(&file, target_rustlib_lib.join(file.file_name().unwrap()));
-                }
-            }
+impl SysrootTarget {
+    fn install_into_sysroot(&self, sysroot: &Path) {
+        if self.libs.is_empty() {
+            return;
         }
-        SysrootKind::Clif => {
-            build_clif_sysroot_for_triple(dirs, channel, host_triple, &cg_clif_dylib_path, None);
-
-            if host_triple != target_triple {
-                // When cross-compiling it is often necessary to manually pick the right linker
-                let linker = match target_triple {
-                    "aarch64-unknown-linux-gnu" => Some("aarch64-linux-gnu-gcc"),
-                    "s390x-unknown-linux-gnu" => Some("s390x-linux-gnu-gcc"),
-                    _ => None,
-                };
-                build_clif_sysroot_for_triple(
-                    dirs,
-                    channel,
-                    target_triple,
-                    &cg_clif_dylib_path,
-                    linker,
-                );
-            }
 
-            // Copy std for the host to the lib dir. This is necessary for the jit mode to find
-            // libstd.
-            for file in fs::read_dir(host_rustlib_lib).unwrap() {
-                let file = file.unwrap().path();
-                let filename = file.file_name().unwrap().to_str().unwrap();
-                if filename.contains("std-") && !filename.contains(".rlib") {
-                    try_hard_link(&file, LIB_DIR.to_path(dirs).join(file.file_name().unwrap()));
-                }
-            }
+        let target_rustlib_lib = sysroot.join("lib").join("rustlib").join(&self.triple).join("lib");
+        fs::create_dir_all(&target_rustlib_lib).unwrap();
+
+        for lib in &self.libs {
+            try_hard_link(lib, target_rustlib_lib.join(lib.file_name().unwrap()));
         }
     }
 }
 
-// FIXME move to download/ or dist/
-pub(crate) static SYSROOT_RUSTC_VERSION: RelPath = RelPath::BUILD_SYSROOT.join("rustc_version");
-pub(crate) static SYSROOT_SRC: RelPath = RelPath::BUILD_SYSROOT.join("sysroot_src");
-static STANDARD_LIBRARY: CargoProject = CargoProject::new(&RelPath::BUILD_SYSROOT, "build_sysroot");
+pub(crate) static ORIG_BUILD_SYSROOT: RelPath = RelPath::SOURCE.join("build_sysroot");
+pub(crate) static BUILD_SYSROOT: RelPath = RelPath::DOWNLOAD.join("sysroot");
+pub(crate) static SYSROOT_RUSTC_VERSION: RelPath = BUILD_SYSROOT.join("rustc_version");
+pub(crate) static SYSROOT_SRC: RelPath = BUILD_SYSROOT.join("sysroot_src");
+pub(crate) static STANDARD_LIBRARY: CargoProject =
+    CargoProject::new(&BUILD_SYSROOT, "build_sysroot");
+pub(crate) static RTSTARTUP_SYSROOT: RelPath = RelPath::BUILD.join("rtstartup");
 
+#[must_use]
+fn build_sysroot_for_triple(
+    dirs: &Dirs,
+    channel: &str,
+    compiler: Compiler,
+    cg_clif_dylib_path: &Path,
+    sysroot_kind: SysrootKind,
+) -> SysrootTarget {
+    match sysroot_kind {
+        SysrootKind::None => build_rtstartup(dirs, &compiler)
+            .unwrap_or(SysrootTarget { triple: compiler.triple, libs: vec![] }),
+        SysrootKind::Llvm => build_llvm_sysroot_for_triple(compiler),
+        SysrootKind::Clif => {
+            build_clif_sysroot_for_triple(dirs, channel, compiler, &cg_clif_dylib_path)
+        }
+    }
+}
+
+#[must_use]
+fn build_llvm_sysroot_for_triple(compiler: Compiler) -> SysrootTarget {
+    let default_sysroot = super::rustc_info::get_default_sysroot(&compiler.rustc);
+
+    let mut target_libs = SysrootTarget { triple: compiler.triple, libs: vec![] };
+
+    for entry in fs::read_dir(
+        default_sysroot.join("lib").join("rustlib").join(&target_libs.triple).join("lib"),
+    )
+    .unwrap()
+    {
+        let entry = entry.unwrap();
+        if entry.file_type().unwrap().is_dir() {
+            continue;
+        }
+        let file = entry.path();
+        let file_name_str = file.file_name().unwrap().to_str().unwrap();
+        if (file_name_str.contains("rustc_")
+            && !file_name_str.contains("rustc_std_workspace_")
+            && !file_name_str.contains("rustc_demangle"))
+            || file_name_str.contains("chalk")
+            || file_name_str.contains("tracing")
+            || file_name_str.contains("regex")
+        {
+            // These are large crates that are part of the rustc-dev component and are not
+            // necessary to run regular programs.
+            continue;
+        }
+        target_libs.libs.push(file);
+    }
+
+    target_libs
+}
+
+#[must_use]
 fn build_clif_sysroot_for_triple(
     dirs: &Dirs,
     channel: &str,
-    triple: &str,
+    mut compiler: Compiler,
     cg_clif_dylib_path: &Path,
-    linker: Option<&str>,
-) {
+) -> SysrootTarget {
     match fs::read_to_string(SYSROOT_RUSTC_VERSION.to_path(dirs)) {
         Err(e) => {
             eprintln!("Failed to get rustc version for patched sysroot source: {}", e);
@@ -165,7 +206,7 @@ fn build_clif_sysroot_for_triple(
             process::exit(1);
         }
         Ok(source_version) => {
-            let rustc_version = get_rustc_version();
+            let rustc_version = get_rustc_version(&compiler.rustc);
             if source_version != rustc_version {
                 eprintln!("The patched sysroot source is outdated");
                 eprintln!("Source version: {}", source_version.trim());
@@ -176,29 +217,32 @@ fn build_clif_sysroot_for_triple(
         }
     }
 
-    let build_dir = STANDARD_LIBRARY.target_dir(dirs).join(triple).join(channel);
+    let mut target_libs = SysrootTarget { triple: compiler.triple.clone(), libs: vec![] };
+
+    if let Some(rtstartup_target_libs) = build_rtstartup(dirs, &compiler) {
+        rtstartup_target_libs.install_into_sysroot(&RTSTARTUP_SYSROOT.to_path(dirs));
+
+        target_libs.libs.extend(rtstartup_target_libs.libs);
+    }
+
+    let build_dir = STANDARD_LIBRARY.target_dir(dirs).join(&compiler.triple).join(channel);
 
     if !super::config::get_bool("keep_sysroot") {
         // Cleanup the deps dir, but keep build scripts and the incremental cache for faster
         // recompilation as they are not affected by changes in cg_clif.
-        if build_dir.join("deps").exists() {
-            fs::remove_dir_all(build_dir.join("deps")).unwrap();
-        }
+        remove_dir_if_exists(&build_dir.join("deps"));
     }
 
     // Build sysroot
-    let mut rustflags = "-Zforce-unstable-if-unmarked -Cpanic=abort".to_string();
+    let mut rustflags = " -Zforce-unstable-if-unmarked -Cpanic=abort".to_string();
     rustflags.push_str(&format!(" -Zcodegen-backend={}", cg_clif_dylib_path.to_str().unwrap()));
-    rustflags.push_str(&format!(" --sysroot={}", DIST_DIR.to_path(dirs).to_str().unwrap()));
+    // Necessary for MinGW to find rsbegin.o and rsend.o
+    rustflags
+        .push_str(&format!(" --sysroot={}", RTSTARTUP_SYSROOT.to_path(dirs).to_str().unwrap()));
     if channel == "release" {
         rustflags.push_str(" -Zmir-opt-level=3");
     }
-    if let Some(linker) = linker {
-        use std::fmt::Write;
-        write!(rustflags, " -Clinker={}", linker).unwrap();
-    }
-    let mut compiler = Compiler::with_triple(triple.to_owned());
-    compiler.rustflags = rustflags;
+    compiler.rustflags += &rustflags;
     let mut build_cmd = STANDARD_LIBRARY.build(&compiler, dirs);
     if channel == "release" {
         build_cmd.arg("--release");
@@ -206,7 +250,6 @@ fn build_clif_sysroot_for_triple(
     build_cmd.env("__CARGO_DEFAULT_LIB_METADATA", "cg_clif");
     spawn_and_wait(build_cmd);
 
-    // Copy all relevant files to the sysroot
     for entry in fs::read_dir(build_dir.join("deps")).unwrap() {
         let entry = entry.unwrap();
         if let Some(ext) = entry.path().extension() {
@@ -216,9 +259,35 @@ fn build_clif_sysroot_for_triple(
         } else {
             continue;
         };
-        try_hard_link(
-            entry.path(),
-            RUSTLIB_DIR.to_path(dirs).join(triple).join("lib").join(entry.file_name()),
-        );
+        target_libs.libs.push(entry.path());
+    }
+
+    target_libs
+}
+
+fn build_rtstartup(dirs: &Dirs, compiler: &Compiler) -> Option<SysrootTarget> {
+    if !compiler.triple.ends_with("windows-gnu") {
+        return None;
     }
+
+    RTSTARTUP_SYSROOT.ensure_fresh(dirs);
+
+    let rtstartup_src = SYSROOT_SRC.to_path(dirs).join("library").join("rtstartup");
+    let mut target_libs = SysrootTarget { triple: compiler.triple.clone(), libs: vec![] };
+
+    for file in ["rsbegin", "rsend"] {
+        let obj = RTSTARTUP_SYSROOT.to_path(dirs).join(format!("{file}.o"));
+        let mut build_rtstartup_cmd = Command::new(&compiler.rustc);
+        build_rtstartup_cmd
+            .arg("--target")
+            .arg(&compiler.triple)
+            .arg("--emit=obj")
+            .arg("-o")
+            .arg(&obj)
+            .arg(rtstartup_src.join(format!("{file}.rs")));
+        spawn_and_wait(build_rtstartup_cmd);
+        target_libs.libs.push(obj.clone());
+    }
+
+    Some(target_libs)
 }
index 1afc9a55c73b5318bbc9ed006899c4f5ab3647c3..8dcbe8de189b25a0c31edb7a8fe5525a5826a359 100644 (file)
@@ -2,9 +2,10 @@
 use std::path::PathBuf;
 use std::process;
 
-use self::utils::is_ci;
+use self::utils::{is_ci, Compiler};
 
 mod abi_cafe;
+mod bench;
 mod build_backend;
 mod build_sysroot;
 mod config;
 mod tests;
 mod utils;
 
-const USAGE: &str = r#"The build system of cg_clif.
-
-USAGE:
-    ./y.rs prepare [--out-dir DIR]
-    ./y.rs build [--debug] [--sysroot none|clif|llvm] [--out-dir DIR] [--no-unstable-features]
-    ./y.rs test [--debug] [--sysroot none|clif|llvm] [--out-dir DIR] [--no-unstable-features]
-
-OPTIONS:
-    --sysroot none|clif|llvm
-            Which sysroot libraries to use:
-            `none` will not include any standard library in the sysroot.
-            `clif` will build the standard library using Cranelift.
-            `llvm` will use the pre-compiled standard library of rustc which is compiled with LLVM.
-
-    --out-dir DIR
-            Specify the directory in which the download, build and dist directories are stored.
-            By default this is the working directory.
-
-    --no-unstable-features
-            fSome features are not yet ready for production usage. This option will disable these
-            features. This includes the JIT mode and inline assembly support.
-"#;
-
 fn usage() {
-    eprintln!("{USAGE}");
+    eprintln!("{}", include_str!("usage.txt"));
 }
 
 macro_rules! arg_error {
@@ -54,6 +32,8 @@ enum Command {
     Prepare,
     Build,
     Test,
+    AbiCafe,
+    Bench,
 }
 
 #[derive(Copy, Clone, Debug)]
@@ -64,12 +44,17 @@ pub(crate) enum SysrootKind {
 }
 
 pub fn main() {
-    env::set_var("CG_CLIF_DISPLAY_CG_TIME", "1");
+    if env::var("RUST_BACKTRACE").is_err() {
+        env::set_var("RUST_BACKTRACE", "1");
+    }
     env::set_var("CG_CLIF_DISABLE_INCR_CACHE", "1");
 
     if is_ci() {
         // Disabling incr comp reduces cache size and incr comp doesn't save as much on CI anyway
         env::set_var("CARGO_BUILD_INCREMENTAL", "false");
+
+        // Enable the Cranelift verifier
+        env::set_var("CG_CLIF_ENABLE_VERIFIER", "1");
     }
 
     let mut args = env::args().skip(1);
@@ -77,6 +62,8 @@ pub fn main() {
         Some("prepare") => Command::Prepare,
         Some("build") => Command::Build,
         Some("test") => Command::Test,
+        Some("abi-cafe") => Command::AbiCafe,
+        Some("bench") => Command::Bench,
         Some(flag) if flag.starts_with('-') => arg_error!("Expected command found flag {}", flag),
         Some(command) => arg_error!("Unknown command {}", command),
         None => {
@@ -112,24 +99,16 @@ pub fn main() {
         }
     }
 
-    let host_triple = if let Ok(host_triple) = std::env::var("HOST_TRIPLE") {
-        host_triple
-    } else if let Some(host_triple) = config::get_value("host") {
-        host_triple
-    } else {
-        rustc_info::get_host_triple()
-    };
-    let target_triple = if let Ok(target_triple) = std::env::var("TARGET_TRIPLE") {
-        if target_triple != "" {
-            target_triple
-        } else {
-            host_triple.clone() // Empty target triple can happen on GHA
-        }
-    } else if let Some(target_triple) = config::get_value("target") {
-        target_triple
-    } else {
-        host_triple.clone()
-    };
+    let bootstrap_host_compiler = Compiler::bootstrap_with_triple(
+        std::env::var("HOST_TRIPLE")
+            .ok()
+            .or_else(|| config::get_value("host"))
+            .unwrap_or_else(|| rustc_info::get_host_triple()),
+    );
+    let target_triple = std::env::var("TARGET_TRIPLE")
+        .ok()
+        .or_else(|| config::get_value("target"))
+        .unwrap_or_else(|| bootstrap_host_compiler.triple.clone());
 
     // FIXME allow changing the location of these dirs using cli arguments
     let current_dir = std::env::current_dir().unwrap();
@@ -157,8 +136,15 @@ pub fn main() {
         process::exit(0);
     }
 
-    let cg_clif_dylib =
-        build_backend::build_backend(&dirs, channel, &host_triple, use_unstable_features);
+    env::set_var("RUSTC", "rustc_should_be_set_explicitly");
+    env::set_var("RUSTDOC", "rustdoc_should_be_set_explicitly");
+
+    let cg_clif_dylib = build_backend::build_backend(
+        &dirs,
+        channel,
+        &bootstrap_host_compiler,
+        use_unstable_features,
+    );
     match command {
         Command::Prepare => {
             // Handled above
@@ -169,28 +155,37 @@ pub fn main() {
                 channel,
                 sysroot_kind,
                 &cg_clif_dylib,
-                &host_triple,
-                &target_triple,
+                &bootstrap_host_compiler,
+                target_triple.clone(),
             );
-
-            abi_cafe::run(
+        }
+        Command::AbiCafe => {
+            if bootstrap_host_compiler.triple != target_triple {
+                eprintln!("Abi-cafe doesn't support cross-compilation");
+                process::exit(1);
+            }
+            abi_cafe::run(channel, sysroot_kind, &dirs, &cg_clif_dylib, &bootstrap_host_compiler);
+        }
+        Command::Build => {
+            build_sysroot::build_sysroot(
+                &dirs,
                 channel,
                 sysroot_kind,
-                &dirs,
                 &cg_clif_dylib,
-                &host_triple,
-                &target_triple,
+                &bootstrap_host_compiler,
+                target_triple,
             );
         }
-        Command::Build => {
+        Command::Bench => {
             build_sysroot::build_sysroot(
                 &dirs,
                 channel,
                 sysroot_kind,
                 &cg_clif_dylib,
-                &host_triple,
-                &target_triple,
+                &bootstrap_host_compiler,
+                target_triple,
             );
+            bench::benchmark(&dirs, &bootstrap_host_compiler);
         }
     }
 }
index e93981f1d64d369b28672c0e61ff5a533c271a23..3290723005dd92b939486489e4acda090b0a8ac0 100644 (file)
@@ -1,6 +1,8 @@
 use std::fs;
 use std::path::PathBuf;
 
+use super::utils::remove_dir_if_exists;
+
 #[derive(Debug, Clone)]
 pub(crate) struct Dirs {
     pub(crate) source_dir: PathBuf,
@@ -42,7 +44,6 @@ impl RelPath {
     pub(crate) const DIST: RelPath = RelPath::Base(PathBase::Dist);
 
     pub(crate) const SCRIPTS: RelPath = RelPath::SOURCE.join("scripts");
-    pub(crate) const BUILD_SYSROOT: RelPath = RelPath::SOURCE.join("build_sysroot");
     pub(crate) const PATCHES: RelPath = RelPath::SOURCE.join("patches");
 
     pub(crate) const fn join(&'static self, suffix: &'static str) -> RelPath {
@@ -62,9 +63,7 @@ pub(crate) fn ensure_exists(&self, dirs: &Dirs) {
 
     pub(crate) fn ensure_fresh(&self, dirs: &Dirs) {
         let path = self.to_path(dirs);
-        if path.exists() {
-            fs::remove_dir_all(&path).unwrap();
-        }
+        remove_dir_if_exists(&path);
         fs::create_dir_all(path).unwrap();
     }
 }
index 8ac67e8f9422823090a97ffab654c0da5a848e12..f25a81dc23459f8e93e4204eb32efb2c80df12e8 100644 (file)
@@ -3,73 +3,55 @@
 use std::path::{Path, PathBuf};
 use std::process::Command;
 
-use super::build_sysroot::{SYSROOT_RUSTC_VERSION, SYSROOT_SRC};
+use super::build_sysroot::{BUILD_SYSROOT, ORIG_BUILD_SYSROOT, SYSROOT_RUSTC_VERSION, SYSROOT_SRC};
 use super::path::{Dirs, RelPath};
-use super::rustc_info::{get_file_name, get_rustc_path, get_rustc_version};
-use super::utils::{copy_dir_recursively, spawn_and_wait, Compiler};
+use super::rustc_info::{get_default_sysroot, get_rustc_version};
+use super::utils::{copy_dir_recursively, git_command, retry_spawn_and_wait, spawn_and_wait};
 
 pub(crate) fn prepare(dirs: &Dirs) {
-    if RelPath::DOWNLOAD.to_path(dirs).exists() {
-        std::fs::remove_dir_all(RelPath::DOWNLOAD.to_path(dirs)).unwrap();
-    }
-    std::fs::create_dir_all(RelPath::DOWNLOAD.to_path(dirs)).unwrap();
+    RelPath::DOWNLOAD.ensure_fresh(dirs);
 
-    prepare_sysroot(dirs);
+    spawn_and_wait(super::build_backend::CG_CLIF.fetch("cargo", dirs));
 
-    // FIXME maybe install this only locally?
-    eprintln!("[INSTALL] hyperfine");
-    Command::new("cargo")
-        .arg("install")
-        .arg("hyperfine")
-        .env_remove("CARGO_TARGET_DIR")
-        .spawn()
-        .unwrap()
-        .wait()
-        .unwrap();
+    prepare_sysroot(dirs);
+    spawn_and_wait(super::build_sysroot::STANDARD_LIBRARY.fetch("cargo", dirs));
+    spawn_and_wait(super::tests::LIBCORE_TESTS.fetch("cargo", dirs));
 
     super::abi_cafe::ABI_CAFE_REPO.fetch(dirs);
+    spawn_and_wait(super::abi_cafe::ABI_CAFE.fetch("cargo", dirs));
     super::tests::RAND_REPO.fetch(dirs);
+    spawn_and_wait(super::tests::RAND.fetch("cargo", dirs));
     super::tests::REGEX_REPO.fetch(dirs);
+    spawn_and_wait(super::tests::REGEX.fetch("cargo", dirs));
     super::tests::PORTABLE_SIMD_REPO.fetch(dirs);
-    super::tests::SIMPLE_RAYTRACER_REPO.fetch(dirs);
-
-    eprintln!("[LLVM BUILD] simple-raytracer");
-    let host_compiler = Compiler::host();
-    let build_cmd = super::tests::SIMPLE_RAYTRACER.build(&host_compiler, dirs);
-    spawn_and_wait(build_cmd);
-    fs::copy(
-        super::tests::SIMPLE_RAYTRACER
-            .target_dir(dirs)
-            .join(&host_compiler.triple)
-            .join("debug")
-            .join(get_file_name("main", "bin")),
-        RelPath::BUILD.to_path(dirs).join(get_file_name("raytracer_cg_llvm", "bin")),
-    )
-    .unwrap();
+    spawn_and_wait(super::tests::PORTABLE_SIMD.fetch("cargo", dirs));
+    super::bench::SIMPLE_RAYTRACER_REPO.fetch(dirs);
+    spawn_and_wait(super::bench::SIMPLE_RAYTRACER.fetch("cargo", dirs));
 }
 
 fn prepare_sysroot(dirs: &Dirs) {
-    let rustc_path = get_rustc_path();
-    let sysroot_src_orig = rustc_path.parent().unwrap().join("../lib/rustlib/src/rust");
-    let sysroot_src = SYSROOT_SRC;
-
+    let sysroot_src_orig = get_default_sysroot(Path::new("rustc")).join("lib/rustlib/src/rust");
     assert!(sysroot_src_orig.exists());
 
-    sysroot_src.ensure_fresh(dirs);
-    fs::create_dir_all(sysroot_src.to_path(dirs).join("library")).unwrap();
     eprintln!("[COPY] sysroot src");
+
+    // FIXME ensure builds error out or update the copy if any of the files copied here change
+    BUILD_SYSROOT.ensure_fresh(dirs);
+    copy_dir_recursively(&ORIG_BUILD_SYSROOT.to_path(dirs), &BUILD_SYSROOT.to_path(dirs));
+
+    fs::create_dir_all(SYSROOT_SRC.to_path(dirs).join("library")).unwrap();
     copy_dir_recursively(
         &sysroot_src_orig.join("library"),
-        &sysroot_src.to_path(dirs).join("library"),
+        &SYSROOT_SRC.to_path(dirs).join("library"),
     );
 
-    let rustc_version = get_rustc_version();
+    let rustc_version = get_rustc_version(Path::new("rustc"));
     fs::write(SYSROOT_RUSTC_VERSION.to_path(dirs), &rustc_version).unwrap();
 
     eprintln!("[GIT] init");
-    init_git_repo(&sysroot_src.to_path(dirs));
+    init_git_repo(&SYSROOT_SRC.to_path(dirs));
 
-    apply_patches(dirs, "sysroot", &sysroot_src.to_path(dirs));
+    apply_patches(dirs, "sysroot", &SYSROOT_SRC.to_path(dirs));
 }
 
 pub(crate) struct GitRepo {
@@ -118,14 +100,14 @@ fn fetch(&self, dirs: &Dirs) {
 fn clone_repo(download_dir: &Path, repo: &str, rev: &str) {
     eprintln!("[CLONE] {}", repo);
     // Ignore exit code as the repo may already have been checked out
-    Command::new("git").arg("clone").arg(repo).arg(&download_dir).spawn().unwrap().wait().unwrap();
+    git_command(None, "clone").arg(repo).arg(download_dir).spawn().unwrap().wait().unwrap();
 
-    let mut clean_cmd = Command::new("git");
-    clean_cmd.arg("checkout").arg("--").arg(".").current_dir(&download_dir);
+    let mut clean_cmd = git_command(download_dir, "checkout");
+    clean_cmd.arg("--").arg(".");
     spawn_and_wait(clean_cmd);
 
-    let mut checkout_cmd = Command::new("git");
-    checkout_cmd.arg("checkout").arg("-q").arg(rev).current_dir(download_dir);
+    let mut checkout_cmd = git_command(download_dir, "checkout");
+    checkout_cmd.arg("-q").arg(rev);
     spawn_and_wait(checkout_cmd);
 }
 
@@ -149,8 +131,22 @@ fn clone_repo_shallow_github(dirs: &Dirs, download_dir: &Path, user: &str, repo:
 
     // Download zip archive
     let mut download_cmd = Command::new("curl");
-    download_cmd.arg("--location").arg("--output").arg(&archive_file).arg(archive_url);
-    spawn_and_wait(download_cmd);
+    download_cmd
+        .arg("--max-time")
+        .arg("600")
+        .arg("-y")
+        .arg("30")
+        .arg("-Y")
+        .arg("10")
+        .arg("--connect-timeout")
+        .arg("30")
+        .arg("--continue-at")
+        .arg("-")
+        .arg("--location")
+        .arg("--output")
+        .arg(&archive_file)
+        .arg(archive_url);
+    retry_spawn_and_wait(5, download_cmd);
 
     // Unpack tar archive
     let mut unpack_cmd = Command::new("tar");
@@ -167,25 +163,16 @@ fn clone_repo_shallow_github(dirs: &Dirs, download_dir: &Path, user: &str, repo:
 }
 
 fn init_git_repo(repo_dir: &Path) {
-    let mut git_init_cmd = Command::new("git");
-    git_init_cmd.arg("init").arg("-q").current_dir(repo_dir);
+    let mut git_init_cmd = git_command(repo_dir, "init");
+    git_init_cmd.arg("-q");
     spawn_and_wait(git_init_cmd);
 
-    let mut git_add_cmd = Command::new("git");
-    git_add_cmd.arg("add").arg(".").current_dir(repo_dir);
+    let mut git_add_cmd = git_command(repo_dir, "add");
+    git_add_cmd.arg(".");
     spawn_and_wait(git_add_cmd);
 
-    let mut git_commit_cmd = Command::new("git");
-    git_commit_cmd
-        .arg("-c")
-        .arg("user.name=Dummy")
-        .arg("-c")
-        .arg("user.email=dummy@example.com")
-        .arg("commit")
-        .arg("-m")
-        .arg("Initial commit")
-        .arg("-q")
-        .current_dir(repo_dir);
+    let mut git_commit_cmd = git_command(repo_dir, "commit");
+    git_commit_cmd.arg("-m").arg("Initial commit").arg("-q");
     spawn_and_wait(git_commit_cmd);
 }
 
@@ -220,16 +207,8 @@ fn apply_patches(dirs: &Dirs, crate_name: &str, target_dir: &Path) {
             target_dir.file_name().unwrap(),
             patch.file_name().unwrap()
         );
-        let mut apply_patch_cmd = Command::new("git");
-        apply_patch_cmd
-            .arg("-c")
-            .arg("user.name=Dummy")
-            .arg("-c")
-            .arg("user.email=dummy@example.com")
-            .arg("am")
-            .arg(patch)
-            .arg("-q")
-            .current_dir(target_dir);
+        let mut apply_patch_cmd = git_command(target_dir, "am");
+        apply_patch_cmd.arg(patch).arg("-q");
         spawn_and_wait(apply_patch_cmd);
     }
 }
index 8e5ab688e131b35325af4fb83a3387b8c6228449..a70453b4422898e31f0030f1613cf7877260e481 100644 (file)
@@ -1,9 +1,9 @@
 use std::path::{Path, PathBuf};
 use std::process::{Command, Stdio};
 
-pub(crate) fn get_rustc_version() -> String {
+pub(crate) fn get_rustc_version(rustc: &Path) -> String {
     let version_info =
-        Command::new("rustc").stderr(Stdio::inherit()).args(&["-V"]).output().unwrap().stdout;
+        Command::new(rustc).stderr(Stdio::inherit()).args(&["-V"]).output().unwrap().stdout;
     String::from_utf8(version_info).unwrap()
 }
 
@@ -23,6 +23,16 @@ pub(crate) fn get_host_triple() -> String {
         .to_owned()
 }
 
+pub(crate) fn get_toolchain_name() -> String {
+    let active_toolchain = Command::new("rustup")
+        .stderr(Stdio::inherit())
+        .args(&["show", "active-toolchain"])
+        .output()
+        .unwrap()
+        .stdout;
+    String::from_utf8(active_toolchain).unwrap().trim().split_once(' ').unwrap().0.to_owned()
+}
+
 pub(crate) fn get_cargo_path() -> PathBuf {
     let cargo_path = Command::new("rustup")
         .stderr(Stdio::inherit())
@@ -53,8 +63,8 @@ pub(crate) fn get_rustdoc_path() -> PathBuf {
     Path::new(String::from_utf8(rustc_path).unwrap().trim()).to_owned()
 }
 
-pub(crate) fn get_default_sysroot() -> PathBuf {
-    let default_sysroot = Command::new("rustc")
+pub(crate) fn get_default_sysroot(rustc: &Path) -> PathBuf {
+    let default_sysroot = Command::new(rustc)
         .stderr(Stdio::inherit())
         .args(&["--print", "sysroot"])
         .output()
@@ -83,12 +93,3 @@ pub(crate) fn get_file_name(crate_name: &str, crate_type: &str) -> String {
     assert!(file_name.contains(crate_name));
     file_name
 }
-
-/// Similar to `get_file_name`, but converts any dashes (`-`) in the `crate_name` to
-/// underscores (`_`). This is specially made for the rustc and cargo wrappers
-/// which have a dash in the name, and that is not allowed in a crate name.
-pub(crate) fn get_wrapper_file_name(crate_name: &str, crate_type: &str) -> String {
-    let crate_name = crate_name.replace('-', "_");
-    let wrapper_name = get_file_name(&crate_name, crate_type);
-    wrapper_name.replace('_', "-")
-}
index 1c372736ed65d9121dccf04ae5bcf504d45127bc..dcfadd737566e20d8a76f0fb8bf393e9b27eb654 100644 (file)
@@ -1,11 +1,10 @@
-use super::build_sysroot;
+use super::bench::SIMPLE_RAYTRACER;
+use super::build_sysroot::{self, SYSROOT_SRC};
 use super::config;
 use super::path::{Dirs, RelPath};
 use super::prepare::GitRepo;
-use super::rustc_info::{get_cargo_path, get_wrapper_file_name};
-use super::utils::{
-    hyperfine_command, spawn_and_wait, spawn_and_wait_with_input, CargoProject, Compiler,
-};
+use super::rustc_info::get_host_triple;
+use super::utils::{spawn_and_wait, spawn_and_wait_with_input, CargoProject, Compiler};
 use super::SysrootKind;
 use std::env;
 use std::ffi::OsStr;
 
 struct TestCase {
     config: &'static str,
-    func: &'static dyn Fn(&TestRunner),
+    cmd: TestCaseCmd,
+}
+
+enum TestCaseCmd {
+    Custom { func: &'static dyn Fn(&TestRunner) },
+    BuildLib { source: &'static str, crate_types: &'static str },
+    BuildBinAndRun { source: &'static str, args: &'static [&'static str] },
+    JitBin { source: &'static str, args: &'static str },
 }
 
 impl TestCase {
-    const fn new(config: &'static str, func: &'static dyn Fn(&TestRunner)) -> Self {
-        Self { config, func }
+    // FIXME reduce usage of custom test case commands
+    const fn custom(config: &'static str, func: &'static dyn Fn(&TestRunner)) -> Self {
+        Self { config, cmd: TestCaseCmd::Custom { func } }
+    }
+
+    const fn build_lib(
+        config: &'static str,
+        source: &'static str,
+        crate_types: &'static str,
+    ) -> Self {
+        Self { config, cmd: TestCaseCmd::BuildLib { source, crate_types } }
+    }
+
+    const fn build_bin_and_run(
+        config: &'static str,
+        source: &'static str,
+        args: &'static [&'static str],
+    ) -> Self {
+        Self { config, cmd: TestCaseCmd::BuildBinAndRun { source, args } }
+    }
+
+    const fn jit_bin(config: &'static str, source: &'static str, args: &'static str) -> Self {
+        Self { config, cmd: TestCaseCmd::JitBin { source, args } }
     }
 }
 
 const NO_SYSROOT_SUITE: &[TestCase] = &[
-    TestCase::new("build.mini_core", &|runner| {
-        runner.run_rustc([
-            "example/mini_core.rs",
-            "--crate-name",
-            "mini_core",
-            "--crate-type",
-            "lib,dylib",
-            "--target",
-            &runner.target_compiler.triple,
-        ]);
-    }),
-    TestCase::new("build.example", &|runner| {
-        runner.run_rustc([
-            "example/example.rs",
-            "--crate-type",
-            "lib",
-            "--target",
-            &runner.target_compiler.triple,
-        ]);
-    }),
-    TestCase::new("jit.mini_core_hello_world", &|runner| {
-        let mut jit_cmd = runner.rustc_command([
-            "-Zunstable-options",
-            "-Cllvm-args=mode=jit",
-            "-Cprefer-dynamic",
-            "example/mini_core_hello_world.rs",
-            "--cfg",
-            "jit",
-            "--target",
-            &runner.target_compiler.triple,
-        ]);
-        jit_cmd.env("CG_CLIF_JIT_ARGS", "abc bcd");
-        spawn_and_wait(jit_cmd);
-
-        eprintln!("[JIT-lazy] mini_core_hello_world");
-        let mut jit_cmd = runner.rustc_command([
-            "-Zunstable-options",
-            "-Cllvm-args=mode=jit-lazy",
-            "-Cprefer-dynamic",
-            "example/mini_core_hello_world.rs",
-            "--cfg",
-            "jit",
-            "--target",
-            &runner.target_compiler.triple,
-        ]);
-        jit_cmd.env("CG_CLIF_JIT_ARGS", "abc bcd");
-        spawn_and_wait(jit_cmd);
-    }),
-    TestCase::new("aot.mini_core_hello_world", &|runner| {
-        runner.run_rustc([
-            "example/mini_core_hello_world.rs",
-            "--crate-name",
-            "mini_core_hello_world",
-            "--crate-type",
-            "bin",
-            "-g",
-            "--target",
-            &runner.target_compiler.triple,
-        ]);
-        runner.run_out_command("mini_core_hello_world", ["abc", "bcd"]);
-    }),
+    TestCase::build_lib("build.mini_core", "example/mini_core.rs", "lib,dylib"),
+    TestCase::build_lib("build.example", "example/example.rs", "lib"),
+    TestCase::jit_bin("jit.mini_core_hello_world", "example/mini_core_hello_world.rs", "abc bcd"),
+    TestCase::build_bin_and_run(
+        "aot.mini_core_hello_world",
+        "example/mini_core_hello_world.rs",
+        &["abc", "bcd"],
+    ),
 ];
 
 const BASE_SYSROOT_SUITE: &[TestCase] = &[
-    TestCase::new("aot.arbitrary_self_types_pointers_and_wrappers", &|runner| {
-        runner.run_rustc([
-            "example/arbitrary_self_types_pointers_and_wrappers.rs",
-            "--crate-name",
-            "arbitrary_self_types_pointers_and_wrappers",
-            "--crate-type",
-            "bin",
-            "--target",
-            &runner.target_compiler.triple,
-        ]);
-        runner.run_out_command("arbitrary_self_types_pointers_and_wrappers", []);
-    }),
-    TestCase::new("aot.issue_91827_extern_types", &|runner| {
-        runner.run_rustc([
-            "example/issue-91827-extern-types.rs",
-            "--crate-name",
-            "issue_91827_extern_types",
-            "--crate-type",
-            "bin",
-            "--target",
-            &runner.target_compiler.triple,
-        ]);
-        runner.run_out_command("issue_91827_extern_types", []);
-    }),
-    TestCase::new("build.alloc_system", &|runner| {
-        runner.run_rustc([
-            "example/alloc_system.rs",
-            "--crate-type",
-            "lib",
-            "--target",
-            &runner.target_compiler.triple,
-        ]);
-    }),
-    TestCase::new("aot.alloc_example", &|runner| {
-        runner.run_rustc([
-            "example/alloc_example.rs",
-            "--crate-type",
-            "bin",
-            "--target",
-            &runner.target_compiler.triple,
-        ]);
-        runner.run_out_command("alloc_example", []);
-    }),
-    TestCase::new("jit.std_example", &|runner| {
-        runner.run_rustc([
-            "-Zunstable-options",
-            "-Cllvm-args=mode=jit",
-            "-Cprefer-dynamic",
-            "example/std_example.rs",
-            "--target",
-            &runner.target_compiler.triple,
-        ]);
-
-        eprintln!("[JIT-lazy] std_example");
-        runner.run_rustc([
-            "-Zunstable-options",
-            "-Cllvm-args=mode=jit-lazy",
-            "-Cprefer-dynamic",
-            "example/std_example.rs",
-            "--target",
-            &runner.target_compiler.triple,
-        ]);
-    }),
-    TestCase::new("aot.std_example", &|runner| {
-        runner.run_rustc([
-            "example/std_example.rs",
-            "--crate-type",
-            "bin",
-            "--target",
-            &runner.target_compiler.triple,
-        ]);
-        runner.run_out_command("std_example", ["arg"]);
-    }),
-    TestCase::new("aot.dst_field_align", &|runner| {
-        runner.run_rustc([
-            "example/dst-field-align.rs",
-            "--crate-name",
-            "dst_field_align",
-            "--crate-type",
-            "bin",
-            "--target",
-            &runner.target_compiler.triple,
-        ]);
-        runner.run_out_command("dst_field_align", []);
-    }),
-    TestCase::new("aot.subslice-patterns-const-eval", &|runner| {
-        runner.run_rustc([
-            "example/subslice-patterns-const-eval.rs",
-            "--crate-type",
-            "bin",
-            "-Cpanic=abort",
-            "--target",
-            &runner.target_compiler.triple,
-        ]);
-        runner.run_out_command("subslice-patterns-const-eval", []);
-    }),
-    TestCase::new("aot.track-caller-attribute", &|runner| {
-        runner.run_rustc([
-            "example/track-caller-attribute.rs",
-            "--crate-type",
-            "bin",
-            "-Cpanic=abort",
-            "--target",
-            &runner.target_compiler.triple,
-        ]);
-        runner.run_out_command("track-caller-attribute", []);
-    }),
-    TestCase::new("aot.float-minmax-pass", &|runner| {
-        runner.run_rustc([
-            "example/float-minmax-pass.rs",
-            "--crate-type",
-            "bin",
-            "-Cpanic=abort",
-            "--target",
-            &runner.target_compiler.triple,
-        ]);
-        runner.run_out_command("float-minmax-pass", []);
-    }),
-    TestCase::new("aot.mod_bench", &|runner| {
-        runner.run_rustc([
-            "example/mod_bench.rs",
-            "--crate-type",
-            "bin",
-            "--target",
-            &runner.target_compiler.triple,
-        ]);
-        runner.run_out_command("mod_bench", []);
-    }),
-    TestCase::new("aot.issue-72793", &|runner| {
-        runner.run_rustc([
-            "example/issue-72793.rs",
-            "--crate-type",
-            "bin",
-            "--target",
-            &runner.target_compiler.triple,
-        ]);
-        runner.run_out_command("issue-72793", []);
-    }),
+    TestCase::build_bin_and_run(
+        "aot.arbitrary_self_types_pointers_and_wrappers",
+        "example/arbitrary_self_types_pointers_and_wrappers.rs",
+        &[],
+    ),
+    TestCase::build_bin_and_run(
+        "aot.issue_91827_extern_types",
+        "example/issue-91827-extern-types.rs",
+        &[],
+    ),
+    TestCase::build_lib("build.alloc_system", "example/alloc_system.rs", "lib"),
+    TestCase::build_bin_and_run("aot.alloc_example", "example/alloc_example.rs", &[]),
+    TestCase::jit_bin("jit.std_example", "example/std_example.rs", ""),
+    TestCase::build_bin_and_run("aot.std_example", "example/std_example.rs", &["arg"]),
+    TestCase::build_bin_and_run("aot.dst_field_align", "example/dst-field-align.rs", &[]),
+    TestCase::build_bin_and_run(
+        "aot.subslice-patterns-const-eval",
+        "example/subslice-patterns-const-eval.rs",
+        &[],
+    ),
+    TestCase::build_bin_and_run(
+        "aot.track-caller-attribute",
+        "example/track-caller-attribute.rs",
+        &[],
+    ),
+    TestCase::build_bin_and_run("aot.float-minmax-pass", "example/float-minmax-pass.rs", &[]),
+    TestCase::build_bin_and_run("aot.mod_bench", "example/mod_bench.rs", &[]),
+    TestCase::build_bin_and_run("aot.issue-72793", "example/issue-72793.rs", &[]),
 ];
 
 pub(crate) static RAND_REPO: GitRepo =
     GitRepo::github("rust-random", "rand", "0f933f9c7176e53b2a3c7952ded484e1783f0bf1", "rand");
 
-static RAND: CargoProject = CargoProject::new(&RAND_REPO.source_dir(), "rand");
+pub(crate) static RAND: CargoProject = CargoProject::new(&RAND_REPO.source_dir(), "rand");
 
 pub(crate) static REGEX_REPO: GitRepo =
     GitRepo::github("rust-lang", "regex", "341f207c1071f7290e3f228c710817c280c8dca1", "regex");
 
-static REGEX: CargoProject = CargoProject::new(&REGEX_REPO.source_dir(), "regex");
+pub(crate) static REGEX: CargoProject = CargoProject::new(&REGEX_REPO.source_dir(), "regex");
 
 pub(crate) static PORTABLE_SIMD_REPO: GitRepo = GitRepo::github(
     "rust-lang",
     "portable-simd",
-    "d5cd4a8112d958bd3a252327e0d069a6363249bd",
+    "582239ac3b32007613df04d7ffa78dc30f4c5645",
     "portable-simd",
 );
 
-static PORTABLE_SIMD: CargoProject =
+pub(crate) static PORTABLE_SIMD: CargoProject =
     CargoProject::new(&PORTABLE_SIMD_REPO.source_dir(), "portable_simd");
 
-pub(crate) static SIMPLE_RAYTRACER_REPO: GitRepo = GitRepo::github(
-    "ebobby",
-    "simple-raytracer",
-    "804a7a21b9e673a482797aa289a18ed480e4d813",
-    "<none>",
-);
-
-pub(crate) static SIMPLE_RAYTRACER: CargoProject =
-    CargoProject::new(&SIMPLE_RAYTRACER_REPO.source_dir(), "simple_raytracer");
-
-static LIBCORE_TESTS: CargoProject =
-    CargoProject::new(&RelPath::BUILD_SYSROOT.join("sysroot_src/library/core/tests"), "core_tests");
+pub(crate) static LIBCORE_TESTS: CargoProject =
+    CargoProject::new(&SYSROOT_SRC.join("library/core/tests"), "core_tests");
 
 const EXTENDED_SYSROOT_SUITE: &[TestCase] = &[
-    TestCase::new("test.rust-random/rand", &|runner| {
-        spawn_and_wait(RAND.clean(&runner.target_compiler.cargo, &runner.dirs));
+    TestCase::custom("test.rust-random/rand", &|runner| {
+        RAND.clean(&runner.dirs);
 
         if runner.is_native {
             eprintln!("[TEST] rust-random/rand");
@@ -280,60 +134,12 @@ const fn new(config: &'static str, func: &'static dyn Fn(&TestRunner)) -> Self {
             spawn_and_wait(build_cmd);
         }
     }),
-    TestCase::new("bench.simple-raytracer", &|runner| {
-        let run_runs = env::var("RUN_RUNS").unwrap_or("10".to_string()).parse().unwrap();
-
-        if runner.is_native {
-            eprintln!("[BENCH COMPILE] ebobby/simple-raytracer");
-            let cargo_clif = RelPath::DIST
-                .to_path(&runner.dirs)
-                .join(get_wrapper_file_name("cargo-clif", "bin"));
-            let manifest_path = SIMPLE_RAYTRACER.manifest_path(&runner.dirs);
-            let target_dir = SIMPLE_RAYTRACER.target_dir(&runner.dirs);
-
-            let clean_cmd = format!(
-                "cargo clean --manifest-path {manifest_path} --target-dir {target_dir}",
-                manifest_path = manifest_path.display(),
-                target_dir = target_dir.display(),
-            );
-            let llvm_build_cmd = format!(
-                "cargo build --manifest-path {manifest_path} --target-dir {target_dir}",
-                manifest_path = manifest_path.display(),
-                target_dir = target_dir.display(),
-            );
-            let clif_build_cmd = format!(
-                "{cargo_clif} build --manifest-path {manifest_path} --target-dir {target_dir}",
-                cargo_clif = cargo_clif.display(),
-                manifest_path = manifest_path.display(),
-                target_dir = target_dir.display(),
-            );
-
-            let bench_compile =
-                hyperfine_command(1, run_runs, Some(&clean_cmd), &llvm_build_cmd, &clif_build_cmd);
-
-            spawn_and_wait(bench_compile);
-
-            eprintln!("[BENCH RUN] ebobby/simple-raytracer");
-            fs::copy(
-                target_dir.join("debug").join("main"),
-                RelPath::BUILD.to_path(&runner.dirs).join("raytracer_cg_clif"),
-            )
-            .unwrap();
-
-            let mut bench_run =
-                hyperfine_command(0, run_runs, None, "./raytracer_cg_llvm", "./raytracer_cg_clif");
-            bench_run.current_dir(RelPath::BUILD.to_path(&runner.dirs));
-            spawn_and_wait(bench_run);
-        } else {
-            spawn_and_wait(SIMPLE_RAYTRACER.clean(&runner.target_compiler.cargo, &runner.dirs));
-            eprintln!("[BENCH COMPILE] ebobby/simple-raytracer (skipped)");
-            eprintln!("[COMPILE] ebobby/simple-raytracer");
-            spawn_and_wait(SIMPLE_RAYTRACER.build(&runner.target_compiler, &runner.dirs));
-            eprintln!("[BENCH RUN] ebobby/simple-raytracer (skipped)");
-        }
+    TestCase::custom("test.simple-raytracer", &|runner| {
+        SIMPLE_RAYTRACER.clean(&runner.dirs);
+        spawn_and_wait(SIMPLE_RAYTRACER.build(&runner.target_compiler, &runner.dirs));
     }),
-    TestCase::new("test.libcore", &|runner| {
-        spawn_and_wait(LIBCORE_TESTS.clean(&runner.host_compiler.cargo, &runner.dirs));
+    TestCase::custom("test.libcore", &|runner| {
+        LIBCORE_TESTS.clean(&runner.dirs);
 
         if runner.is_native {
             spawn_and_wait(LIBCORE_TESTS.test(&runner.target_compiler, &runner.dirs));
@@ -344,8 +150,8 @@ const fn new(config: &'static str, func: &'static dyn Fn(&TestRunner)) -> Self {
             spawn_and_wait(build_cmd);
         }
     }),
-    TestCase::new("test.regex-shootout-regex-dna", &|runner| {
-        spawn_and_wait(REGEX.clean(&runner.target_compiler.cargo, &runner.dirs));
+    TestCase::custom("test.regex-shootout-regex-dna", &|runner| {
+        REGEX.clean(&runner.dirs);
 
         // newer aho_corasick versions throw a deprecation warning
         let lint_rust_flags = format!("{} --cap-lints warn", runner.target_compiler.rustflags);
@@ -364,9 +170,10 @@ const fn new(config: &'static str, func: &'static dyn Fn(&TestRunner)) -> Self {
                 REGEX.source_dir(&runner.dirs).join("examples").join("regexdna-input.txt"),
             )
             .unwrap();
-            let expected_path =
-                REGEX.source_dir(&runner.dirs).join("examples").join("regexdna-output.txt");
-            let expected = fs::read_to_string(&expected_path).unwrap();
+            let expected = fs::read_to_string(
+                REGEX.source_dir(&runner.dirs).join("examples").join("regexdna-output.txt"),
+            )
+            .unwrap();
 
             let output = spawn_and_wait_with_input(run_cmd, input);
             // Make sure `[codegen mono items] start` doesn't poison the diff
@@ -379,27 +186,16 @@ const fn new(config: &'static str, func: &'static dyn Fn(&TestRunner)) -> Self {
 
             let output_matches = expected.lines().eq(output.lines());
             if !output_matches {
-                let res_path = REGEX.source_dir(&runner.dirs).join("res.txt");
-                fs::write(&res_path, &output).unwrap();
-
-                if cfg!(windows) {
-                    println!("Output files don't match!");
-                    println!("Expected Output:\n{}", expected);
-                    println!("Actual Output:\n{}", output);
-                } else {
-                    let mut diff = Command::new("diff");
-                    diff.arg("-u");
-                    diff.arg(res_path);
-                    diff.arg(expected_path);
-                    spawn_and_wait(diff);
-                }
+                println!("Output files don't match!");
+                println!("Expected Output:\n{}", expected);
+                println!("Actual Output:\n{}", output);
 
                 std::process::exit(1);
             }
         }
     }),
-    TestCase::new("test.regex", &|runner| {
-        spawn_and_wait(REGEX.clean(&runner.host_compiler.cargo, &runner.dirs));
+    TestCase::custom("test.regex", &|runner| {
+        REGEX.clean(&runner.dirs);
 
         // newer aho_corasick versions throw a deprecation warning
         let lint_rust_flags = format!("{} --cap-lints warn", runner.target_compiler.rustflags);
@@ -425,8 +221,8 @@ const fn new(config: &'static str, func: &'static dyn Fn(&TestRunner)) -> Self {
             spawn_and_wait(build_cmd);
         }
     }),
-    TestCase::new("test.portable-simd", &|runner| {
-        spawn_and_wait(PORTABLE_SIMD.clean(&runner.host_compiler.cargo, &runner.dirs));
+    TestCase::custom("test.portable-simd", &|runner| {
+        PORTABLE_SIMD.clean(&runner.dirs);
 
         let mut build_cmd = PORTABLE_SIMD.build(&runner.target_compiler, &runner.dirs);
         build_cmd.arg("--all-targets");
@@ -445,21 +241,22 @@ pub(crate) fn run_tests(
     channel: &str,
     sysroot_kind: SysrootKind,
     cg_clif_dylib: &Path,
-    host_triple: &str,
-    target_triple: &str,
+    bootstrap_host_compiler: &Compiler,
+    target_triple: String,
 ) {
-    let runner = TestRunner::new(dirs.clone(), host_triple.to_string(), target_triple.to_string());
-
     if config::get_bool("testsuite.no_sysroot") {
-        build_sysroot::build_sysroot(
+        let target_compiler = build_sysroot::build_sysroot(
             dirs,
             channel,
             SysrootKind::None,
             cg_clif_dylib,
-            &host_triple,
-            &target_triple,
+            bootstrap_host_compiler,
+            target_triple.clone(),
         );
 
+        let runner =
+            TestRunner::new(dirs.clone(), target_compiler, get_host_triple() == target_triple);
+
         BUILD_EXAMPLE_OUT_DIR.ensure_fresh(dirs);
         runner.run_testsuite(NO_SYSROOT_SUITE);
     } else {
@@ -470,26 +267,29 @@ pub(crate) fn run_tests(
     let run_extended_sysroot = config::get_bool("testsuite.extended_sysroot");
 
     if run_base_sysroot || run_extended_sysroot {
-        build_sysroot::build_sysroot(
+        let target_compiler = build_sysroot::build_sysroot(
             dirs,
             channel,
             sysroot_kind,
             cg_clif_dylib,
-            &host_triple,
-            &target_triple,
+            bootstrap_host_compiler,
+            target_triple.clone(),
         );
-    }
 
-    if run_base_sysroot {
-        runner.run_testsuite(BASE_SYSROOT_SUITE);
-    } else {
-        eprintln!("[SKIP] base_sysroot tests");
-    }
+        let runner =
+            TestRunner::new(dirs.clone(), target_compiler, get_host_triple() == target_triple);
 
-    if run_extended_sysroot {
-        runner.run_testsuite(EXTENDED_SYSROOT_SUITE);
-    } else {
-        eprintln!("[SKIP] extended_sysroot tests");
+        if run_base_sysroot {
+            runner.run_testsuite(BASE_SYSROOT_SUITE);
+        } else {
+            eprintln!("[SKIP] base_sysroot tests");
+        }
+
+        if run_extended_sysroot {
+            runner.run_testsuite(EXTENDED_SYSROOT_SUITE);
+        } else {
+            eprintln!("[SKIP] extended_sysroot tests");
+        }
     }
 }
 
@@ -497,84 +297,34 @@ struct TestRunner {
     is_native: bool,
     jit_supported: bool,
     dirs: Dirs,
-    host_compiler: Compiler,
     target_compiler: Compiler,
 }
 
 impl TestRunner {
-    pub fn new(dirs: Dirs, host_triple: String, target_triple: String) -> Self {
-        let is_native = host_triple == target_triple;
-        let jit_supported =
-            target_triple.contains("x86_64") && is_native && !host_triple.contains("windows");
-
-        let rustc_clif =
-            RelPath::DIST.to_path(&dirs).join(get_wrapper_file_name("rustc-clif", "bin"));
-        let rustdoc_clif =
-            RelPath::DIST.to_path(&dirs).join(get_wrapper_file_name("rustdoc-clif", "bin"));
-
-        let mut rustflags = env::var("RUSTFLAGS").ok().unwrap_or("".to_string());
-        let mut runner = vec![];
-
-        if !is_native {
-            match target_triple.as_str() {
-                "aarch64-unknown-linux-gnu" => {
-                    // We are cross-compiling for aarch64. Use the correct linker and run tests in qemu.
-                    rustflags = format!("-Clinker=aarch64-linux-gnu-gcc{}", rustflags);
-                    runner = vec![
-                        "qemu-aarch64".to_owned(),
-                        "-L".to_owned(),
-                        "/usr/aarch64-linux-gnu".to_owned(),
-                    ];
-                }
-                "s390x-unknown-linux-gnu" => {
-                    // We are cross-compiling for s390x. Use the correct linker and run tests in qemu.
-                    rustflags = format!("-Clinker=s390x-linux-gnu-gcc{}", rustflags);
-                    runner = vec![
-                        "qemu-s390x".to_owned(),
-                        "-L".to_owned(),
-                        "/usr/s390x-linux-gnu".to_owned(),
-                    ];
-                }
-                "x86_64-pc-windows-gnu" => {
-                    // We are cross-compiling for Windows. Run tests in wine.
-                    runner = vec!["wine".to_owned()];
-                }
-                _ => {
-                    println!("Unknown non-native platform");
-                }
-            }
+    pub fn new(dirs: Dirs, mut target_compiler: Compiler, is_native: bool) -> Self {
+        if let Ok(rustflags) = env::var("RUSTFLAGS") {
+            target_compiler.rustflags.push(' ');
+            target_compiler.rustflags.push_str(&rustflags);
+        }
+        if let Ok(rustdocflags) = env::var("RUSTDOCFLAGS") {
+            target_compiler.rustdocflags.push(' ');
+            target_compiler.rustdocflags.push_str(&rustdocflags);
         }
 
         // FIXME fix `#[linkage = "extern_weak"]` without this
-        if target_triple.contains("darwin") {
-            rustflags = format!("{} -Clink-arg=-undefined -Clink-arg=dynamic_lookup", rustflags);
+        if target_compiler.triple.contains("darwin") {
+            target_compiler.rustflags.push_str(" -Clink-arg=-undefined -Clink-arg=dynamic_lookup");
         }
 
-        let host_compiler = Compiler {
-            cargo: get_cargo_path(),
-            rustc: rustc_clif.clone(),
-            rustdoc: rustdoc_clif.clone(),
-            rustflags: String::new(),
-            rustdocflags: String::new(),
-            triple: host_triple,
-            runner: vec![],
-        };
-
-        let target_compiler = Compiler {
-            cargo: get_cargo_path(),
-            rustc: rustc_clif,
-            rustdoc: rustdoc_clif,
-            rustflags: rustflags.clone(),
-            rustdocflags: rustflags,
-            triple: target_triple,
-            runner,
-        };
-
-        Self { is_native, jit_supported, dirs, host_compiler, target_compiler }
+        let jit_supported = is_native
+            && target_compiler.triple.contains("x86_64")
+            && !target_compiler.triple.contains("windows");
+
+        Self { is_native, jit_supported, dirs, target_compiler }
     }
 
     pub fn run_testsuite(&self, tests: &[TestCase]) {
-        for &TestCase { config, func } in tests {
+        for TestCase { config, cmd } in tests {
             let (tag, testname) = config.split_once('.').unwrap();
             let tag = tag.to_uppercase();
             let is_jit_test = tag == "JIT";
@@ -586,7 +336,47 @@ pub fn run_testsuite(&self, tests: &[TestCase]) {
                 eprintln!("[{tag}] {testname}");
             }
 
-            func(self);
+            match *cmd {
+                TestCaseCmd::Custom { func } => func(self),
+                TestCaseCmd::BuildLib { source, crate_types } => {
+                    self.run_rustc([source, "--crate-type", crate_types]);
+                }
+                TestCaseCmd::BuildBinAndRun { source, args } => {
+                    self.run_rustc([source]);
+                    self.run_out_command(
+                        source.split('/').last().unwrap().split('.').next().unwrap(),
+                        args,
+                    );
+                }
+                TestCaseCmd::JitBin { source, args } => {
+                    let mut jit_cmd = self.rustc_command([
+                        "-Zunstable-options",
+                        "-Cllvm-args=mode=jit",
+                        "-Cprefer-dynamic",
+                        source,
+                        "--cfg",
+                        "jit",
+                    ]);
+                    if !args.is_empty() {
+                        jit_cmd.env("CG_CLIF_JIT_ARGS", args);
+                    }
+                    spawn_and_wait(jit_cmd);
+
+                    eprintln!("[JIT-lazy] {testname}");
+                    let mut jit_cmd = self.rustc_command([
+                        "-Zunstable-options",
+                        "-Cllvm-args=mode=jit-lazy",
+                        "-Cprefer-dynamic",
+                        source,
+                        "--cfg",
+                        "jit",
+                    ]);
+                    if !args.is_empty() {
+                        jit_cmd.env("CG_CLIF_JIT_ARGS", args);
+                    }
+                    spawn_and_wait(jit_cmd);
+                }
+            }
         }
     }
 
@@ -603,6 +393,9 @@ fn rustc_command<I, S>(&self, args: I) -> Command
         cmd.arg("--out-dir");
         cmd.arg(format!("{}", BUILD_EXAMPLE_OUT_DIR.to_path(&self.dirs).display()));
         cmd.arg("-Cdebuginfo=2");
+        cmd.arg("--target");
+        cmd.arg(&self.target_compiler.triple);
+        cmd.arg("-Cpanic=abort");
         cmd.args(args);
         cmd
     }
@@ -615,10 +408,7 @@ fn run_rustc<I, S>(&self, args: I)
         spawn_and_wait(self.rustc_command(args));
     }
 
-    fn run_out_command<'a, I>(&self, name: &str, args: I)
-    where
-        I: IntoIterator<Item = &'a str>,
-    {
+    fn run_out_command<'a>(&self, name: &str, args: &[&str]) {
         let mut full_cmd = vec![];
 
         // Prepend the RUN_WRAPPER's
@@ -630,7 +420,7 @@ fn run_out_command<'a, I>(&self, name: &str, args: I)
             BUILD_EXAMPLE_OUT_DIR.to_path(&self.dirs).join(name).to_str().unwrap().to_string(),
         );
 
-        for arg in args.into_iter() {
+        for arg in args {
             full_cmd.push(arg.to_string());
         }
 
diff --git a/compiler/rustc_codegen_cranelift/build_system/usage.txt b/compiler/rustc_codegen_cranelift/build_system/usage.txt
new file mode 100644 (file)
index 0000000..ab98ccc
--- /dev/null
@@ -0,0 +1,35 @@
+The build system of cg_clif.
+
+USAGE:
+    ./y.rs prepare [--out-dir DIR]
+    ./y.rs build [--debug] [--sysroot none|clif|llvm] [--out-dir DIR] [--no-unstable-features]
+    ./y.rs test [--debug] [--sysroot none|clif|llvm] [--out-dir DIR] [--no-unstable-features]
+    ./y.rs abi-cafe [--debug] [--sysroot none|clif|llvm] [--out-dir DIR] [--no-unstable-features]
+    ./y.rs bench [--debug] [--sysroot none|clif|llvm] [--out-dir DIR] [--no-unstable-features]
+
+OPTIONS:
+    --debug
+            Build cg_clif and the standard library in debug mode rather than release mode.
+            Warning: An unoptimized cg_clif is very slow.
+
+    --sysroot none|clif|llvm
+            Which sysroot libraries to use:
+            `none` will not include any standard library in the sysroot.
+            `clif` will build the standard library using Cranelift.
+            `llvm` will use the pre-compiled standard library of rustc which is compiled with LLVM.
+
+    --out-dir DIR
+            Specify the directory in which the download, build and dist directories are stored.
+            By default this is the working directory.
+
+    --no-unstable-features
+            Some features are not yet ready for production usage. This option will disable these
+            features. This includes the JIT mode and inline assembly support.
+
+REQUIREMENTS:
+    * Rustup: The build system has a hard coded dependency on rustup to install the right nightly
+      version and make sure it is used where necessary.
+    * Git: `./y.rs prepare` uses git for applying patches and on Windows for downloading test repos.
+    * Curl and tar (non-Windows only): Used by `./y.rs prepare` to download a single commit for
+      repos. Git will be used to clone the whole repo when using Windows.
+    * [Hyperfine](https://github.com/sharkdp/hyperfine/): Used for benchmarking with `./y.rs bench`.
index 2be70e8e421b2961e97b53c99f38c83256940365..da2a94a0a4ff84a3b307c22213e1813fd03ca55f 100644 (file)
@@ -1,12 +1,13 @@
 use std::env;
 use std::fs;
-use std::io::Write;
+use std::io::{self, Write};
 use std::path::{Path, PathBuf};
 use std::process::{self, Command, Stdio};
 
 use super::path::{Dirs, RelPath};
-use super::rustc_info::{get_cargo_path, get_host_triple, get_rustc_path, get_rustdoc_path};
+use super::rustc_info::{get_cargo_path, get_rustc_path, get_rustdoc_path};
 
+#[derive(Clone, Debug)]
 pub(crate) struct Compiler {
     pub(crate) cargo: PathBuf,
     pub(crate) rustc: PathBuf,
@@ -18,27 +19,47 @@ pub(crate) struct Compiler {
 }
 
 impl Compiler {
-    pub(crate) fn host() -> Compiler {
+    pub(crate) fn bootstrap_with_triple(triple: String) -> Compiler {
         Compiler {
             cargo: get_cargo_path(),
             rustc: get_rustc_path(),
             rustdoc: get_rustdoc_path(),
             rustflags: String::new(),
             rustdocflags: String::new(),
-            triple: get_host_triple(),
+            triple,
             runner: vec![],
         }
     }
 
-    pub(crate) fn with_triple(triple: String) -> Compiler {
-        Compiler {
-            cargo: get_cargo_path(),
-            rustc: get_rustc_path(),
-            rustdoc: get_rustdoc_path(),
-            rustflags: String::new(),
-            rustdocflags: String::new(),
-            triple,
-            runner: vec![],
+    pub(crate) fn set_cross_linker_and_runner(&mut self) {
+        match self.triple.as_str() {
+            "aarch64-unknown-linux-gnu" => {
+                // We are cross-compiling for aarch64. Use the correct linker and run tests in qemu.
+                self.rustflags += " -Clinker=aarch64-linux-gnu-gcc";
+                self.rustdocflags += " -Clinker=aarch64-linux-gnu-gcc";
+                self.runner = vec![
+                    "qemu-aarch64".to_owned(),
+                    "-L".to_owned(),
+                    "/usr/aarch64-linux-gnu".to_owned(),
+                ];
+            }
+            "s390x-unknown-linux-gnu" => {
+                // We are cross-compiling for s390x. Use the correct linker and run tests in qemu.
+                self.rustflags += " -Clinker=s390x-linux-gnu-gcc";
+                self.rustdocflags += " -Clinker=s390x-linux-gnu-gcc";
+                self.runner = vec![
+                    "qemu-s390x".to_owned(),
+                    "-L".to_owned(),
+                    "/usr/s390x-linux-gnu".to_owned(),
+                ];
+            }
+            "x86_64-pc-windows-gnu" => {
+                // We are cross-compiling for Windows. Run tests in wine.
+                self.runner = vec!["wine".to_owned()];
+            }
+            _ => {
+                println!("Unknown non-native platform");
+            }
         }
     }
 }
@@ -65,6 +86,7 @@ pub(crate) fn target_dir(&self, dirs: &Dirs) -> PathBuf {
         RelPath::BUILD.join(self.target).to_path(dirs)
     }
 
+    #[must_use]
     fn base_cmd(&self, command: &str, cargo: &Path, dirs: &Dirs) -> Command {
         let mut cmd = Command::new(cargo);
 
@@ -72,11 +94,13 @@ fn base_cmd(&self, command: &str, cargo: &Path, dirs: &Dirs) -> Command {
             .arg("--manifest-path")
             .arg(self.manifest_path(dirs))
             .arg("--target-dir")
-            .arg(self.target_dir(dirs));
+            .arg(self.target_dir(dirs))
+            .arg("--frozen");
 
         cmd
     }
 
+    #[must_use]
     fn build_cmd(&self, command: &str, compiler: &Compiler, dirs: &Dirs) -> Command {
         let mut cmd = self.base_cmd(command, &compiler.cargo, dirs);
 
@@ -105,9 +129,8 @@ pub(crate) fn fetch(&self, cargo: impl AsRef<Path>, dirs: &Dirs) -> Command {
         cmd
     }
 
-    #[must_use]
-    pub(crate) fn clean(&self, cargo: &Path, dirs: &Dirs) -> Command {
-        self.base_cmd("clean", cargo, dirs)
+    pub(crate) fn clean(&self, dirs: &Dirs) {
+        let _ = fs::remove_dir_all(self.target_dir(dirs));
     }
 
     #[must_use]
@@ -153,6 +176,23 @@ pub(crate) fn hyperfine_command(
     bench
 }
 
+#[must_use]
+pub(crate) fn git_command<'a>(repo_dir: impl Into<Option<&'a Path>>, cmd: &str) -> Command {
+    let mut git_cmd = Command::new("git");
+    git_cmd
+        .arg("-c")
+        .arg("user.name=Dummy")
+        .arg("-c")
+        .arg("user.email=dummy@example.com")
+        .arg("-c")
+        .arg("core.autocrlf=false")
+        .arg(cmd);
+    if let Some(repo_dir) = repo_dir.into() {
+        git_cmd.current_dir(repo_dir);
+    }
+    git_cmd
+}
+
 #[track_caller]
 pub(crate) fn try_hard_link(src: impl AsRef<Path>, dst: impl AsRef<Path>) {
     let src = src.as_ref();
@@ -169,6 +209,22 @@ pub(crate) fn spawn_and_wait(mut cmd: Command) {
     }
 }
 
+// Based on the retry function in rust's src/ci/shared.sh
+#[track_caller]
+pub(crate) fn retry_spawn_and_wait(tries: u64, mut cmd: Command) {
+    for i in 1..tries + 1 {
+        if i != 1 {
+            println!("Command failed. Attempt {i}/{tries}:");
+        }
+        if cmd.spawn().unwrap().wait().unwrap().success() {
+            return;
+        }
+        std::thread::sleep(std::time::Duration::from_secs(i * 5));
+    }
+    println!("The command has failed after {tries} attempts.");
+    process::exit(1);
+}
+
 #[track_caller]
 pub(crate) fn spawn_and_wait_with_input(mut cmd: Command, input: String) -> String {
     let mut child = cmd
@@ -190,6 +246,14 @@ pub(crate) fn spawn_and_wait_with_input(mut cmd: Command, input: String) -> Stri
     String::from_utf8(output.stdout).unwrap()
 }
 
+pub(crate) fn remove_dir_if_exists(path: &Path) {
+    match fs::remove_dir_all(&path) {
+        Ok(()) => {}
+        Err(err) if err.kind() == io::ErrorKind::NotFound => {}
+        Err(err) => panic!("Failed to remove {path}: {err}", path = path.display()),
+    }
+}
+
 pub(crate) fn copy_dir_recursively(from: &Path, to: &Path) {
     for entry in fs::read_dir(from).unwrap() {
         let entry = entry.unwrap();
index 1760e5836ecce00a48f7a0236748dfb94329fce0..cdfc2e143e6748247d056e11488b5adae5ea21f7 100755 (executable)
@@ -1,10 +1,9 @@
 #!/usr/bin/env bash
 set -e
 
-rm -rf build_sysroot/{sysroot_src/,target/,compiler-builtins/,rustc_version}
-rm -rf target/ build/ dist/ perf.data{,.old} y.bin
-rm -rf download/
+rm -rf target/ download/ build/ dist/ y.bin y.bin.dSYM y.exe y.pdb
 
 # Kept for now in case someone updates their checkout of cg_clif before running clean_all.sh
 # FIXME remove at some point in the future
 rm -rf rand/ regex/ simple-raytracer/ portable-simd/ abi-checker/ abi-cafe/
+rm -rf build_sysroot/{sysroot_src/,target/,compiler-builtins/,rustc_version}
index 258b67e931476850a25cab17bbc2c3300a243821..d49cc90791a5d5fb01a81bbf7aeb905405681d55 100644 (file)
@@ -44,10 +44,8 @@ aot.issue-72793
 
 testsuite.extended_sysroot
 test.rust-random/rand
-bench.simple-raytracer
+test.simple-raytracer
 test.libcore
 test.regex-shootout-regex-dna
 test.regex
 test.portable-simd
-
-testsuite.abi-cafe
diff --git a/compiler/rustc_codegen_cranelift/patches/0001-portable-simd-Disable-unsupported-tests.patch b/compiler/rustc_codegen_cranelift/patches/0001-portable-simd-Disable-unsupported-tests.patch
deleted file mode 100644 (file)
index 89e2b61..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-From b742f03694b920cc14400727d54424e8e1b60928 Mon Sep 17 00:00:00 2001
-From: bjorn3 <bjorn3@users.noreply.github.com>
-Date: Thu, 18 Nov 2021 19:28:40 +0100
-Subject: [PATCH] Disable unsupported tests
-
----
- crates/core_simd/src/elements/int.rs     | 8 ++++++++
- crates/core_simd/src/elements/uint.rs    | 4 ++++
- crates/core_simd/src/masks/full_masks.rs | 6 ++++++
- crates/core_simd/src/vector.rs           | 2 ++
- crates/core_simd/tests/masks.rs          | 3 ---
- 5 files changed, 20 insertions(+), 3 deletions(-)
-
-diff --git a/crates/core_simd/src/vector.rs b/crates/core_simd/src/vector.rs
-index e8e8f68..7173c24 100644
---- a/crates/core_simd/src/vector.rs
-+++ b/crates/core_simd/src/vector.rs
-@@ -250,6 +250,7 @@ where
-         unsafe { intrinsics::simd_cast(self) }
-     }
-+    /*
-     /// Reads from potentially discontiguous indices in `slice` to construct a SIMD vector.
-     /// If an index is out-of-bounds, the lane is instead selected from the `or` vector.
-     ///
-@@ -473,6 +474,7 @@ where
-             // Cleared ☢️ *mut T Zone
-         }
-     }
-+    */
- }
- impl<T, const LANES: usize> Copy for Simd<T, LANES>
--- 
-2.25.1
index 8d9ee3f25c49db03b35c65208fe8fc6740c63b63..865aa833a5eef4c01754916a1534d54c84ec175f 100644 (file)
@@ -18,7 +18,7 @@ new file mode 100644
 index 0000000..46fd999
 --- /dev/null
 +++ b/library/core/tests/Cargo.toml
-@@ -0,0 +1,11 @@
+@@ -0,0 +1,12 @@
 +[package]
 +name = "core"
 +version = "0.0.0"
@@ -29,6 +29,7 @@ index 0000000..46fd999
 +path = "lib.rs"
 +
 +[dependencies]
-+rand = "0.7"
++rand = { version = "0.8.5", default-features = false }
++rand_xorshift = { version = "0.3.0", default-features = false }
 --
 2.21.0 (Apple Git-122)
index d8f28dbcc15c8c43d9631834b087f34ed547cebb..77345b9a17c6edca7102326001fcef783e74a1c9 100644 (file)
@@ -1,3 +1,3 @@
 [toolchain]
-channel = "nightly-2022-12-13"
+channel = "nightly-2023-01-20"
 components = ["rust-src", "rustc-dev", "llvm-tools-preview"]
index 9362b47fa6d83137701069fc9c9aced1a9b0ab22..c993430b830b6ebe3d4c1fc919f50fd043f57311 100644 (file)
@@ -26,7 +26,7 @@ fn main() {
     env::set_var("RUSTDOCFLAGS", env::var("RUSTDOCFLAGS").unwrap_or(String::new()) + &rustflags);
 
     // Ensure that the right toolchain is used
-    env::set_var("RUSTUP_TOOLCHAIN", env!("RUSTUP_TOOLCHAIN"));
+    env::set_var("RUSTUP_TOOLCHAIN", env!("TOOLCHAIN_NAME"));
 
     let args: Vec<_> = match env::args().nth(1).as_deref() {
         Some("jit") => {
index 3abfcd8ddc824e493c5f3a3f4086c6a9b4c989f4..c187f54a60e775a0b2a5bca42406390035f6310d 100644 (file)
@@ -24,7 +24,7 @@ fn main() {
     }
 
     // Ensure that the right toolchain is used
-    env::set_var("RUSTUP_TOOLCHAIN", env!("RUSTUP_TOOLCHAIN"));
+    env::set_var("RUSTUP_TOOLCHAIN", env!("TOOLCHAIN_NAME"));
 
     #[cfg(unix)]
     Command::new("rustc").args(args).exec();
index a19d72acfa83e037ac857e1719c3ca1a988895f9..a6528ac41aee08f9f57ae4e396af40c99b239728 100644 (file)
@@ -24,7 +24,7 @@ fn main() {
     }
 
     // Ensure that the right toolchain is used
-    env::set_var("RUSTUP_TOOLCHAIN", env!("RUSTUP_TOOLCHAIN"));
+    env::set_var("RUSTUP_TOOLCHAIN", env!("TOOLCHAIN_NAME"));
 
     #[cfg(unix)]
     Command::new("rustdoc").args(args).exec();
index bc4c06ed7d2988e6d28810d11ead10c7c8d05022..34e3981b5381f5ceeb7e5df8d6a4f6d94ee87b06 100755 (executable)
@@ -17,10 +17,10 @@ case $1 in
         done
 
         ./clean_all.sh
-        ./y.rs prepare
 
-        (cd build_sysroot && cargo update)
+        ./y.rs prepare
 
+        (cd download/sysroot && cargo update && cargo fetch && cp Cargo.lock ../../build_sysroot/)
         ;;
     "commit")
         git add rust-toolchain build_sysroot/Cargo.lock
index 6c64b7de7daa10d863a903a186e0ee9c4846aeed..a08e80dd19abc74bf93036d1707059325464b86e 100644 (file)
@@ -10,7 +10,7 @@ git fetch
 git checkout -- .
 git checkout "$(rustc -V | cut -d' ' -f3 | tr -d '(')"
 
-git am ../patches/*-sysroot-*.patch
+git -c user.name=Dummy -c user.email=dummy@example.com am ../patches/*-sysroot-*.patch
 
 git apply - <<EOF
 diff --git a/library/alloc/Cargo.toml b/library/alloc/Cargo.toml
@@ -25,8 +25,8 @@ index d95b5b7f17f..00b6f0e3635 100644
 +compiler_builtins = { version = "0.1.66", features = ['rustc-dep-of-std', 'no-asm'] }
 
  [dev-dependencies]
- rand = "0.7"
- rand_xorshift = "0.2"
+ rand = { version = "0.8.5", default-features = false, features = ["alloc"] }
+ rand_xorshift = "0.3.0"
 EOF
 
 cat > config.toml <<EOF
@@ -51,7 +51,7 @@ popd
 # FIXME remove once inline asm is fully supported
 export RUSTFLAGS="$RUSTFLAGS --cfg=rustix_use_libc"
 
-export CFG_VIRTUAL_RUST_SOURCE_BASE_DIR="$(cd build_sysroot/sysroot_src; pwd)"
+export CFG_VIRTUAL_RUST_SOURCE_BASE_DIR="$(cd download/sysroot/sysroot_src; pwd)"
 
 # Allow the testsuite to use llvm tools
 host_triple=$(rustc -vV | grep host | cut -d: -f2 | tr -d " ")
index 12ecb8cf4e17d6473d36610183c6e5224d196db9..07c9ae6ee9ff2c1f4340ac0ead9c68879f82ba4e 100755 (executable)
@@ -11,7 +11,7 @@ pushd rust
 command -v rg >/dev/null 2>&1 || cargo install ripgrep
 
 rm -r tests/ui/{extern/,unsized-locals/,lto/,linkage*} || true
-for test in $(rg --files-with-matches "lto|// needs-asm-support|// needs-unwind" tests/{ui,incremental}); do
+for test in $(rg --files-with-matches "lto|// needs-asm-support|// needs-unwind" tests/{codegen-units,ui,incremental}); do
   rm $test
 done
 
@@ -32,20 +32,13 @@ rm tests/incremental/issue-80691-bad-eval-cache.rs # -Cpanic=abort causes abort
 # requires compiling with -Cpanic=unwind
 rm -r tests/ui/macros/rfc-2011-nicer-assert-messages/
 rm -r tests/run-make/test-benches
+rm tests/ui/test-attrs/test-type.rs
 
 # vendor intrinsics
 rm tests/ui/sse2.rs # cpuid not supported, so sse2 not detected
 rm tests/ui/intrinsics/const-eval-select-x86_64.rs # requires x86_64 vendor intrinsics
 rm tests/ui/simd/array-type.rs # "Index argument for `simd_insert` is not a constant"
-rm tests/ui/simd/intrinsic/generic-bitmask-pass.rs # simd_bitmask unimplemented
-rm tests/ui/simd/intrinsic/generic-as.rs # simd_as unimplemented
-rm tests/ui/simd/intrinsic/generic-arithmetic-saturating-pass.rs # simd_saturating_add unimplemented
 rm tests/ui/simd/intrinsic/float-math-pass.rs # simd_fcos unimplemented
-rm tests/ui/simd/intrinsic/generic-gather-pass.rs # simd_gather unimplemented
-rm tests/ui/simd/intrinsic/generic-select-pass.rs # simd_select_bitmask unimplemented
-rm tests/ui/simd/issue-85915-simd-ptrs.rs # simd_gather unimplemented
-rm tests/ui/simd/issue-89193.rs # simd_gather unimplemented
-rm tests/ui/simd/simd-bitmask.rs # simd_bitmask unimplemented
 
 # exotic linkages
 rm tests/ui/issues/issue-33992.rs # unsupported linkages
@@ -64,10 +57,7 @@ rm tests/ui/intrinsics/intrinsic-nearby.rs # unimplemented nearbyintf32 and near
 rm tests/ui/target-feature/missing-plusminus.rs # error not implemented
 rm tests/ui/fn/dyn-fn-alignment.rs # wants a 256 byte alignment
 rm -r tests/run-make/emit-named-files # requires full --emit support
-rm tests/ui/abi/stack-probes.rs # stack probes not yet implemented
-rm tests/ui/simd/intrinsic/ptr-cast.rs # simd_expose_addr intrinsic unimplemented
 rm -r tests/run-make/repr128-dwarf # debuginfo test
-rm tests/codegen-units/item-collection/asm-sym.rs # requires support for sym in asm!()
 
 # optimization tests
 # ==================
@@ -88,6 +78,20 @@ rm tests/ui/mir/mir_raw_fat_ptr.rs # same
 rm tests/ui/consts/issue-33537.rs # same
 rm tests/ui/layout/valid_range_oob.rs # different ICE message
 
+rm tests/ui/consts/issue-miri-1910.rs # different error message
+rm tests/ui/consts/offset_ub.rs # same
+rm tests/ui/intrinsics/panic-uninitialized-zeroed.rs # same
+rm tests/ui/lint/lint-const-item-mutation.rs # same
+rm tests/ui/pattern/usefulness/doc-hidden-non-exhaustive.rs # same
+rm tests/ui/suggestions/derive-trait-for-method-call.rs # same
+rm tests/ui/typeck/issue-46112.rs # same
+
+rm tests/ui/proc-macro/crt-static.rs # extra warning about -Cpanic=abort for proc macros
+rm tests/ui/proc-macro/proc-macro-deprecated-attr.rs # same
+rm tests/ui/proc-macro/quote-debug.rs # same
+rm tests/ui/proc-macro/no-missing-docs.rs # same
+rm tests/ui/rust-2018/proc-macro-crate-in-paths.rs # same
+
 # doesn't work due to the way the rustc test suite is invoked.
 # should work when using ./x.py test the way it is intended
 # ============================================================
@@ -102,23 +106,20 @@ rm -r tests/ui/consts/missing_span_in_backtrace.rs # expects sysroot source to b
 # ============
 rm tests/incremental/spike-neg1.rs # errors out for some reason
 rm tests/incremental/spike-neg2.rs # same
-rm tests/ui/issues/issue-74564-if-expr-stack-overflow.rs # gives a stackoverflow before the backend runs
-rm tests/ui/mir/ssa-analysis-regression-50041.rs # produces ICE
-rm tests/ui/type-alias-impl-trait/assoc-projection-ice.rs # produces ICE
 
 rm tests/ui/simd/intrinsic/generic-reduction-pass.rs # simd_reduce_add_unordered doesn't accept an accumulator for integer vectors
 
-rm tests/ui/runtime/out-of-stack.rs # SIGSEGV instead of SIGABRT for some reason (#1301)
+rm tests/ui/simd/intrinsic/generic-as.rs # crash when accessing vector type filed (#1318)
+rm tests/ui/simd/simd-bitmask.rs # crash
+
+rm tests/ui/dyn-star/dyn-star-to-dyn.rs
+rm tests/ui/dyn-star/dispatch-on-pin-mut.rs
 
 # bugs in the test suite
 # ======================
 rm tests/ui/backtrace.rs # TODO warning
 rm tests/ui/simple_global_asm.rs # TODO add needs-asm-support
-rm tests/ui/test-attrs/test-type.rs # TODO panic message on stderr. correct stdout
-# not sure if this is actually a bug in the test suite, but the symbol list shows the function without leading _ for some reason
-rm -r tests/run-make/native-link-modifier-bundle
 rm tests/ui/process/nofile-limit.rs # TODO some AArch64 linking issue
-rm tests/ui/dyn-star/dispatch-on-pin-mut.rs # TODO failed assertion in vtable::get_ptr_and_method_ref
 
 rm tests/ui/stdio-is-blocking.rs # really slow with unoptimized libstd
 
index 65cc6b4376713d8c7e855c2fca1f833894a3cd09..3c34585d4191e6ef1eaa80b82dd06dc578972e9a 100644 (file)
@@ -7,6 +7,7 @@
 use cranelift_module::ModuleError;
 use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
 use rustc_middle::ty::layout::FnAbiOf;
+use rustc_session::Session;
 use rustc_target::abi::call::{Conv, FnAbi};
 use rustc_target::spec::abi::Abi;
 
@@ -22,7 +23,7 @@ fn clif_sig_from_fn_abi<'tcx>(
     default_call_conv: CallConv,
     fn_abi: &FnAbi<'tcx, Ty<'tcx>>,
 ) -> Signature {
-    let call_conv = conv_to_call_conv(fn_abi.conv, default_call_conv);
+    let call_conv = conv_to_call_conv(tcx.sess, fn_abi.conv, default_call_conv);
 
     let inputs = fn_abi.args.iter().map(|arg_abi| arg_abi.get_abi_param(tcx).into_iter()).flatten();
 
@@ -33,24 +34,32 @@ fn clif_sig_from_fn_abi<'tcx>(
     Signature { params, returns, call_conv }
 }
 
-pub(crate) fn conv_to_call_conv(c: Conv, default_call_conv: CallConv) -> CallConv {
+pub(crate) fn conv_to_call_conv(sess: &Session, c: Conv, default_call_conv: CallConv) -> CallConv {
     match c {
         Conv::Rust | Conv::C => default_call_conv,
         Conv::RustCold => CallConv::Cold,
         Conv::X86_64SysV => CallConv::SystemV,
         Conv::X86_64Win64 => CallConv::WindowsFastcall,
-        Conv::ArmAapcs
-        | Conv::CCmseNonSecureCall
-        | Conv::Msp430Intr
+
+        // Should already get a back compat warning
+        Conv::X86Fastcall | Conv::X86Stdcall | Conv::X86ThisCall | Conv::X86VectorCall => {
+            default_call_conv
+        }
+
+        Conv::X86Intr => sess.fatal("x86-interrupt call conv not yet implemented"),
+
+        Conv::ArmAapcs => sess.fatal("aapcs call conv not yet implemented"),
+        Conv::CCmseNonSecureCall => {
+            sess.fatal("C-cmse-nonsecure-call call conv is not yet implemented");
+        }
+
+        Conv::Msp430Intr
         | Conv::PtxKernel
-        | Conv::X86Fastcall
-        | Conv::X86Intr
-        | Conv::X86Stdcall
-        | Conv::X86ThisCall
-        | Conv::X86VectorCall
         | Conv::AmdGpuKernel
         | Conv::AvrInterrupt
-        | Conv::AvrNonBlockingInterrupt => todo!("{:?}", c),
+        | Conv::AvrNonBlockingInterrupt => {
+            unreachable!("tried to use {c:?} call conv which only exists on an unsupported target");
+        }
     }
 }
 
@@ -161,6 +170,12 @@ fn make_local_place<'tcx>(
     layout: TyAndLayout<'tcx>,
     is_ssa: bool,
 ) -> CPlace<'tcx> {
+    if layout.is_unsized() {
+        fx.tcx.sess.span_fatal(
+            fx.mir.local_decls[local].source_info.span,
+            "unsized locals are not yet supported",
+        );
+    }
     let place = if is_ssa {
         if let rustc_target::abi::Abi::ScalarPair(_, _) = layout.abi {
             CPlace::new_var_pair(fx, local, layout)
index 89d955e8bf2e1d84c1a40045d0b063140d325525..d3a8c10657e8d5cdb78f40fdc10695d7685e9c50 100644 (file)
@@ -113,6 +113,8 @@ pub(crate) fn codegen_fn<'tcx>(
     };
 
     tcx.sess.time("codegen clif ir", || codegen_fn_body(&mut fx, start_block));
+    fx.bcx.seal_all_blocks();
+    fx.bcx.finalize();
 
     // Recover all necessary data from fx, before accessing func will prevent future access to it.
     let symbol_name = fx.symbol_name;
@@ -303,6 +305,9 @@ fn codegen_fn_body(fx: &mut FunctionCx<'_, '_, '_>, start_block: Block) {
         let source_info = bb_data.terminator().source_info;
         fx.set_debug_loc(source_info);
 
+        let _print_guard =
+            crate::PrintOnPanic(|| format!("terminator {:?}", bb_data.terminator().kind));
+
         match &bb_data.terminator().kind {
             TerminatorKind::Goto { target } => {
                 if let TerminatorKind::Return = fx.mir[*target].terminator().kind {
@@ -464,7 +469,10 @@ fn codegen_fn_body(fx: &mut FunctionCx<'_, '_, '_>, start_block: Block) {
                     *destination,
                 );
             }
-            TerminatorKind::Resume | TerminatorKind::Abort => {
+            TerminatorKind::Abort => {
+                codegen_panic_cannot_unwind(fx, source_info);
+            }
+            TerminatorKind::Resume => {
                 // FIXME implement unwinding
                 fx.bcx.ins().trap(TrapCode::UnreachableCodeReached);
             }
@@ -487,9 +495,6 @@ fn codegen_fn_body(fx: &mut FunctionCx<'_, '_, '_>, start_block: Block) {
             }
         };
     }
-
-    fx.bcx.seal_all_blocks();
-    fx.bcx.finalize();
 }
 
 fn codegen_stmt<'tcx>(
@@ -932,7 +937,28 @@ pub(crate) fn codegen_panic<'tcx>(
     codegen_panic_inner(fx, rustc_hir::LangItem::Panic, &args, source_info.span);
 }
 
-pub(crate) fn codegen_panic_inner<'tcx>(
+pub(crate) fn codegen_panic_nounwind<'tcx>(
+    fx: &mut FunctionCx<'_, '_, 'tcx>,
+    msg_str: &str,
+    source_info: mir::SourceInfo,
+) {
+    let msg_ptr = fx.anonymous_str(msg_str);
+    let msg_len = fx.bcx.ins().iconst(fx.pointer_type, i64::try_from(msg_str.len()).unwrap());
+    let args = [msg_ptr, msg_len];
+
+    codegen_panic_inner(fx, rustc_hir::LangItem::PanicNounwind, &args, source_info.span);
+}
+
+pub(crate) fn codegen_panic_cannot_unwind<'tcx>(
+    fx: &mut FunctionCx<'_, '_, 'tcx>,
+    source_info: mir::SourceInfo,
+) {
+    let args = [];
+
+    codegen_panic_inner(fx, rustc_hir::LangItem::PanicCannotUnwind, &args, source_info.span);
+}
+
+fn codegen_panic_inner<'tcx>(
     fx: &mut FunctionCx<'_, '_, 'tcx>,
     lang_item: rustc_hir::LangItem,
     args: &[Value],
@@ -949,11 +975,7 @@ pub(crate) fn codegen_panic_inner<'tcx>(
 
     fx.lib_call(
         &*symbol_name,
-        vec![
-            AbiParam::new(fx.pointer_type),
-            AbiParam::new(fx.pointer_type),
-            AbiParam::new(fx.pointer_type),
-        ],
+        args.iter().map(|&arg| AbiParam::new(fx.bcx.func.dfg.value_type(arg))).collect(),
         vec![],
         args,
     );
index 2dcd42fbd8f431833ac46b414c539e40c828f0e8..f41af3a9e636631949be8a616b799a3dfc6644c8 100644 (file)
@@ -35,7 +35,8 @@ pub(crate) fn scalar_to_clif_type(tcx: TyCtxt<'_>, scalar: Scalar) -> Type {
         },
         Primitive::F32 => types::F32,
         Primitive::F64 => types::F64,
-        Primitive::Pointer => pointer_ty(tcx),
+        // FIXME(erikdesjardins): handle non-default addrspace ptr sizes
+        Primitive::Pointer(_) => pointer_ty(tcx),
     }
 }
 
@@ -167,6 +168,15 @@ pub(crate) fn codegen_icmp_imm(
     }
 }
 
+pub(crate) fn codegen_bitcast(fx: &mut FunctionCx<'_, '_, '_>, dst_ty: Type, val: Value) -> Value {
+    let mut flags = MemFlags::new();
+    flags.set_endianness(match fx.tcx.data_layout.endian {
+        rustc_target::abi::Endian::Big => cranelift_codegen::ir::Endianness::Big,
+        rustc_target::abi::Endian::Little => cranelift_codegen::ir::Endianness::Little,
+    });
+    fx.bcx.ins().bitcast(dst_ty, flags, val)
+}
+
 pub(crate) fn type_zero_value(bcx: &mut FunctionBuilder<'_>, ty: Type) -> Value {
     if ty == types::I128 {
         let zero = bcx.ins().iconst(types::I64, 0);
diff --git a/compiler/rustc_codegen_cranelift/src/cranelift_native.rs b/compiler/rustc_codegen_cranelift/src/cranelift_native.rs
new file mode 100644 (file)
index 0000000..6c4efca
--- /dev/null
@@ -0,0 +1,248 @@
+// Vendored from https://github.com/bytecodealliance/wasmtime/blob/b58a197d33f044193c3d608010f5e6ec394ac07e/cranelift/native/src/lib.rs
+// which is licensed as
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+// unlike rustc_codegen_cranelift itself. Also applies a small change to remove #![cfg_attr] that
+// rust's CI complains about and to fix formatting to match rustc.
+// FIXME revert back to the external crate with Cranelift 0.93
+#![allow(warnings)]
+
+//! Performs autodetection of the host for the purposes of running
+//! Cranelift to generate code to run on the same machine.
+
+#![deny(missing_docs, trivial_numeric_casts, unused_extern_crates, unstable_features)]
+#![warn(unused_import_braces)]
+
+use cranelift_codegen::isa;
+use target_lexicon::Triple;
+
+/// Return an `isa` builder configured for the current host
+/// machine, or `Err(())` if the host machine is not supported
+/// in the current configuration.
+pub fn builder() -> Result<isa::Builder, &'static str> {
+    builder_with_options(true)
+}
+
+/// Return an `isa` builder configured for the current host
+/// machine, or `Err(())` if the host machine is not supported
+/// in the current configuration.
+///
+/// Selects the given backend variant specifically; this is
+/// useful when more than oen backend exists for a given target
+/// (e.g., on x86-64).
+pub fn builder_with_options(infer_native_flags: bool) -> Result<isa::Builder, &'static str> {
+    let mut isa_builder = isa::lookup(Triple::host()).map_err(|err| match err {
+        isa::LookupError::SupportDisabled => "support for architecture disabled at compile time",
+        isa::LookupError::Unsupported => "unsupported architecture",
+    })?;
+
+    #[cfg(target_arch = "x86_64")]
+    {
+        use cranelift_codegen::settings::Configurable;
+
+        if !std::is_x86_feature_detected!("sse2") {
+            return Err("x86 support requires SSE2");
+        }
+
+        if !infer_native_flags {
+            return Ok(isa_builder);
+        }
+
+        // These are temporarily enabled by default (see #3810 for
+        // more) so that a default-constructed `Flags` can work with
+        // default Wasmtime features. Otherwise, the user must
+        // explicitly use native flags or turn these on when on x86-64
+        // platforms to avoid a configuration panic. In order for the
+        // "enable if detected" logic below to work, we must turn them
+        // *off* (differing from the default) and then re-enable below
+        // if present.
+        isa_builder.set("has_sse3", "false").unwrap();
+        isa_builder.set("has_ssse3", "false").unwrap();
+        isa_builder.set("has_sse41", "false").unwrap();
+        isa_builder.set("has_sse42", "false").unwrap();
+
+        if std::is_x86_feature_detected!("sse3") {
+            isa_builder.enable("has_sse3").unwrap();
+        }
+        if std::is_x86_feature_detected!("ssse3") {
+            isa_builder.enable("has_ssse3").unwrap();
+        }
+        if std::is_x86_feature_detected!("sse4.1") {
+            isa_builder.enable("has_sse41").unwrap();
+        }
+        if std::is_x86_feature_detected!("sse4.2") {
+            isa_builder.enable("has_sse42").unwrap();
+        }
+        if std::is_x86_feature_detected!("popcnt") {
+            isa_builder.enable("has_popcnt").unwrap();
+        }
+        if std::is_x86_feature_detected!("avx") {
+            isa_builder.enable("has_avx").unwrap();
+        }
+        if std::is_x86_feature_detected!("avx2") {
+            isa_builder.enable("has_avx2").unwrap();
+        }
+        if std::is_x86_feature_detected!("fma") {
+            isa_builder.enable("has_fma").unwrap();
+        }
+        if std::is_x86_feature_detected!("bmi1") {
+            isa_builder.enable("has_bmi1").unwrap();
+        }
+        if std::is_x86_feature_detected!("bmi2") {
+            isa_builder.enable("has_bmi2").unwrap();
+        }
+        if std::is_x86_feature_detected!("avx512bitalg") {
+            isa_builder.enable("has_avx512bitalg").unwrap();
+        }
+        if std::is_x86_feature_detected!("avx512dq") {
+            isa_builder.enable("has_avx512dq").unwrap();
+        }
+        if std::is_x86_feature_detected!("avx512f") {
+            isa_builder.enable("has_avx512f").unwrap();
+        }
+        if std::is_x86_feature_detected!("avx512vl") {
+            isa_builder.enable("has_avx512vl").unwrap();
+        }
+        if std::is_x86_feature_detected!("avx512vbmi") {
+            isa_builder.enable("has_avx512vbmi").unwrap();
+        }
+        if std::is_x86_feature_detected!("lzcnt") {
+            isa_builder.enable("has_lzcnt").unwrap();
+        }
+    }
+
+    #[cfg(target_arch = "aarch64")]
+    {
+        use cranelift_codegen::settings::Configurable;
+
+        if !infer_native_flags {
+            return Ok(isa_builder);
+        }
+
+        if std::arch::is_aarch64_feature_detected!("lse") {
+            isa_builder.enable("has_lse").unwrap();
+        }
+
+        if std::arch::is_aarch64_feature_detected!("paca") {
+            isa_builder.enable("has_pauth").unwrap();
+        }
+
+        if cfg!(target_os = "macos") {
+            // Pointer authentication is always available on Apple Silicon.
+            isa_builder.enable("sign_return_address").unwrap();
+            // macOS enforces the use of the B key for return addresses.
+            isa_builder.enable("sign_return_address_with_bkey").unwrap();
+        }
+    }
+
+    // There is no is_s390x_feature_detected macro yet, so for now
+    // we use getauxval from the libc crate directly.
+    #[cfg(all(target_arch = "s390x", target_os = "linux"))]
+    {
+        use cranelift_codegen::settings::Configurable;
+
+        if !infer_native_flags {
+            return Ok(isa_builder);
+        }
+
+        let v = unsafe { libc::getauxval(libc::AT_HWCAP) };
+        const HWCAP_S390X_VXRS_EXT2: libc::c_ulong = 32768;
+        if (v & HWCAP_S390X_VXRS_EXT2) != 0 {
+            isa_builder.enable("has_vxrs_ext2").unwrap();
+            // There is no separate HWCAP bit for mie2, so assume
+            // that any machine with vxrs_ext2 also has mie2.
+            isa_builder.enable("has_mie2").unwrap();
+        }
+    }
+
+    // `is_riscv_feature_detected` is nightly only for now, use
+    // getauxval from the libc crate directly as a temporary measure.
+    #[cfg(all(target_arch = "riscv64", target_os = "linux"))]
+    {
+        use cranelift_codegen::settings::Configurable;
+
+        if !infer_native_flags {
+            return Ok(isa_builder);
+        }
+
+        let v = unsafe { libc::getauxval(libc::AT_HWCAP) };
+
+        const HWCAP_RISCV_EXT_A: libc::c_ulong = 1 << (b'a' - b'a');
+        const HWCAP_RISCV_EXT_C: libc::c_ulong = 1 << (b'c' - b'a');
+        const HWCAP_RISCV_EXT_D: libc::c_ulong = 1 << (b'd' - b'a');
+        const HWCAP_RISCV_EXT_F: libc::c_ulong = 1 << (b'f' - b'a');
+        const HWCAP_RISCV_EXT_M: libc::c_ulong = 1 << (b'm' - b'a');
+        const HWCAP_RISCV_EXT_V: libc::c_ulong = 1 << (b'v' - b'a');
+
+        if (v & HWCAP_RISCV_EXT_A) != 0 {
+            isa_builder.enable("has_a").unwrap();
+        }
+
+        if (v & HWCAP_RISCV_EXT_C) != 0 {
+            isa_builder.enable("has_c").unwrap();
+        }
+
+        if (v & HWCAP_RISCV_EXT_D) != 0 {
+            isa_builder.enable("has_d").unwrap();
+        }
+
+        if (v & HWCAP_RISCV_EXT_F) != 0 {
+            isa_builder.enable("has_f").unwrap();
+
+            // TODO: There doesn't seem to be a bit associated with this extension
+            // rust enables it with the `f` extension:
+            // https://github.com/rust-lang/stdarch/blob/790411f93c4b5eada3c23abb4c9a063fb0b24d99/crates/std_detect/src/detect/os/linux/riscv.rs#L43
+            isa_builder.enable("has_zicsr").unwrap();
+        }
+
+        if (v & HWCAP_RISCV_EXT_M) != 0 {
+            isa_builder.enable("has_m").unwrap();
+        }
+
+        if (v & HWCAP_RISCV_EXT_V) != 0 {
+            isa_builder.enable("has_v").unwrap();
+        }
+
+        // TODO: ZiFencei does not have a bit associated with it
+        // TODO: Zbkb does not have a bit associated with it
+    }
+
+    // squelch warnings about unused mut/variables on some platforms.
+    drop(&mut isa_builder);
+    drop(infer_native_flags);
+
+    Ok(isa_builder)
+}
+
+#[cfg(test)]
+mod tests {
+    use super::builder;
+    use cranelift_codegen::isa::CallConv;
+    use cranelift_codegen::settings;
+
+    #[test]
+    fn test() {
+        if let Ok(isa_builder) = builder() {
+            let flag_builder = settings::builder();
+            let isa = isa_builder.finish(settings::Flags::new(flag_builder)).unwrap();
+
+            if cfg!(all(target_os = "macos", target_arch = "aarch64")) {
+                assert_eq!(isa.default_call_conv(), CallConv::AppleAarch64);
+            } else if cfg!(any(unix, target_os = "nebulet")) {
+                assert_eq!(isa.default_call_conv(), CallConv::SystemV);
+            } else if cfg!(windows) {
+                assert_eq!(isa.default_call_conv(), CallConv::WindowsFastcall);
+            }
+
+            if cfg!(target_pointer_width = "64") {
+                assert_eq!(isa.pointer_bits(), 64);
+            } else if cfg!(target_pointer_width = "32") {
+                assert_eq!(isa.pointer_bits(), 32);
+            } else if cfg!(target_pointer_width = "16") {
+                assert_eq!(isa.pointer_bits(), 16);
+            }
+        }
+    }
+}
+
+/// Version number of this crate.
+pub const VERSION: &str = env!("CARGO_PKG_VERSION");
index 28fbcb15b2b5893ab9ea6912d5047a05a6f293a7..3a7421d8b30d843354e3462d1fec296a7f957035 100644 (file)
 pub(crate) use emit::{DebugReloc, DebugRelocName};
 pub(crate) use unwind::UnwindContext;
 
+pub(crate) fn producer() -> String {
+    format!(
+        "cg_clif (rustc {}, cranelift {})",
+        rustc_interface::util::rustc_version_str().unwrap_or("unknown version"),
+        cranelift_codegen::VERSION,
+    )
+}
+
 pub(crate) struct DebugContext {
     endian: RunTimeEndian,
 
@@ -57,11 +65,7 @@ pub(crate) fn new(tcx: TyCtxt<'_>, isa: &dyn TargetIsa) -> Self {
 
         let mut dwarf = DwarfUnit::new(encoding);
 
-        let producer = format!(
-            "cg_clif (rustc {}, cranelift {})",
-            rustc_interface::util::rustc_version_str().unwrap_or("unknown version"),
-            cranelift_codegen::VERSION,
-        );
+        let producer = producer();
         let comp_dir = tcx
             .sess
             .opts
index f873561c1713f37853821e3548ad6511a7981f58..d4494a9e45de49981df3dcf679809e225132d054 100644 (file)
@@ -108,6 +108,8 @@ pub(crate) fn join(
 
         self.concurrency_limiter.finished();
 
+        sess.abort_if_errors();
+
         (
             CodegenResults {
                 modules,
@@ -169,10 +171,22 @@ fn emit_cgu(
 fn emit_module(
     output_filenames: &OutputFilenames,
     prof: &SelfProfilerRef,
-    object: cranelift_object::object::write::Object<'_>,
+    mut object: cranelift_object::object::write::Object<'_>,
     kind: ModuleKind,
     name: String,
 ) -> Result<CompiledModule, String> {
+    if object.format() == cranelift_object::object::BinaryFormat::Elf {
+        let comment_section = object.add_section(
+            Vec::new(),
+            b".comment".to_vec(),
+            cranelift_object::object::SectionKind::OtherString,
+        );
+        let mut producer = vec![0];
+        producer.extend(crate::debuginfo::producer().as_bytes());
+        producer.push(0);
+        object.set_section_data(comment_section, producer, 1);
+    }
+
     let tmp_file = output_filenames.temp_path(OutputType::Object, Some(&name));
     let mut file = match File::create(&tmp_file) {
         Ok(file) => file,
@@ -399,8 +413,6 @@ pub(crate) fn run_aot(
             .collect::<Vec<_>>()
     });
 
-    tcx.sess.abort_if_errors();
-
     let mut allocator_module = make_module(tcx.sess, &backend_config, "allocator_shim".to_string());
     let mut allocator_unwind_context = UnwindContext::new(allocator_module.isa(), true);
     let created_alloc_shim =
index 7bc161fbe55236a1b03ad08db5a80e274f94d7f8..d2ae6978ca2a8ee84e63410dd0d6d6aa1985461b 100644 (file)
@@ -33,8 +33,8 @@ pub(crate) fn codegen_x86_llvm_intrinsic_call<'tcx>(
 
                 // cast float to int
                 let a_lane = match lane_ty {
-                    types::F32 => fx.bcx.ins().bitcast(types::I32, a_lane),
-                    types::F64 => fx.bcx.ins().bitcast(types::I64, a_lane),
+                    types::F32 => codegen_bitcast(fx, types::I32, a_lane),
+                    types::F64 => codegen_bitcast(fx, types::I64, a_lane),
                     _ => a_lane,
                 };
 
index e4ac89a7bec6b245d17cf41828f392a76df8e4dc..d561cf139b6c9bca3ac97f0d985f006383916322 100644 (file)
@@ -21,6 +21,7 @@ macro_rules! intrinsic_args {
 pub(crate) use cpuid::codegen_cpuid_call;
 pub(crate) use llvm::codegen_llvm_intrinsic_call;
 
+use rustc_middle::ty::layout::HasParamEnv;
 use rustc_middle::ty::print::with_no_trimmed_paths;
 use rustc_middle::ty::subst::SubstsRef;
 use rustc_span::symbol::{kw, sym, Symbol};
@@ -200,7 +201,7 @@ fn bool_to_zero_or_max_uint<'tcx>(
     let mut res = fx.bcx.ins().bmask(int_ty, val);
 
     if ty.is_float() {
-        res = fx.bcx.ins().bitcast(ty, res);
+        res = codegen_bitcast(fx, ty, res);
     }
 
     res
@@ -240,10 +241,9 @@ pub(crate) fn codegen_intrinsic_call<'tcx>(
             substs,
             args,
             destination,
+            target,
             source_info.span,
         );
-        let ret_block = fx.get_block(target);
-        fx.bcx.ins().jump(ret_block, &[]);
     } else if codegen_float_intrinsic_call(fx, intrinsic, args, destination) {
         let ret_block = fx.get_block(target);
         fx.bcx.ins().jump(ret_block, &[]);
@@ -650,7 +650,7 @@ fn codegen_regular_intrinsic_call<'tcx>(
             let layout = fx.layout_of(substs.type_at(0));
             if layout.abi.is_uninhabited() {
                 with_no_trimmed_paths!({
-                    crate::base::codegen_panic(
+                    crate::base::codegen_panic_nounwind(
                         fx,
                         &format!("attempted to instantiate uninhabited type `{}`", layout.ty),
                         source_info,
@@ -659,9 +659,11 @@ fn codegen_regular_intrinsic_call<'tcx>(
                 return;
             }
 
-            if intrinsic == sym::assert_zero_valid && !fx.tcx.permits_zero_init(layout) {
+            if intrinsic == sym::assert_zero_valid
+                && !fx.tcx.permits_zero_init(fx.param_env().and(layout))
+            {
                 with_no_trimmed_paths!({
-                    crate::base::codegen_panic(
+                    crate::base::codegen_panic_nounwind(
                         fx,
                         &format!(
                             "attempted to zero-initialize type `{}`, which is invalid",
@@ -674,10 +676,10 @@ fn codegen_regular_intrinsic_call<'tcx>(
             }
 
             if intrinsic == sym::assert_mem_uninitialized_valid
-                && !fx.tcx.permits_uninit_init(layout)
+                && !fx.tcx.permits_uninit_init(fx.param_env().and(layout))
             {
                 with_no_trimmed_paths!({
-                    crate::base::codegen_panic(
+                    crate::base::codegen_panic_nounwind(
                         fx,
                         &format!(
                             "attempted to leave type `{}` uninitialized, which is invalid",
index 14f5e9187399fac76f2a64d0147f2f647a904929..b33eb29754ab70e3fab43eeef4109e6962f99683 100644 (file)
@@ -24,6 +24,7 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>(
     _substs: SubstsRef<'tcx>,
     args: &[mir::Operand<'tcx>],
     ret: CPlace<'tcx>,
+    target: BasicBlock,
     span: Span,
 ) {
     match intrinsic {
@@ -277,16 +278,15 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>(
             } else {
                 fx.tcx.sess.span_warn(span, "Index argument for `simd_extract` is not a constant");
                 let trap_block = fx.bcx.create_block();
-                let dummy_block = fx.bcx.create_block();
                 let true_ = fx.bcx.ins().iconst(types::I8, 1);
                 fx.bcx.ins().brnz(true_, trap_block, &[]);
-                fx.bcx.ins().jump(dummy_block, &[]);
+                let ret_block = fx.get_block(target);
+                fx.bcx.ins().jump(ret_block, &[]);
                 fx.bcx.switch_to_block(trap_block);
                 crate::trap::trap_unimplemented(
                     fx,
                     "Index argument for `simd_extract` is not a constant",
                 );
-                fx.bcx.switch_to_block(dummy_block);
                 return;
             };
 
@@ -770,11 +770,119 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>(
             });
         }
 
-        // simd_arith_offset
-        // simd_scatter
-        // simd_gather
+        sym::simd_expose_addr | sym::simd_from_exposed_addr | sym::simd_cast_ptr => {
+            intrinsic_args!(fx, args => (arg); intrinsic);
+            ret.write_cvalue_transmute(fx, arg);
+        }
+
+        sym::simd_arith_offset => {
+            intrinsic_args!(fx, args => (ptr, offset); intrinsic);
+
+            let (lane_count, ptr_lane_ty) = ptr.layout().ty.simd_size_and_type(fx.tcx);
+            let pointee_ty = ptr_lane_ty.builtin_deref(true).unwrap().ty;
+            let pointee_size = fx.layout_of(pointee_ty).size.bytes();
+            let (ret_lane_count, ret_lane_ty) = ret.layout().ty.simd_size_and_type(fx.tcx);
+            let ret_lane_layout = fx.layout_of(ret_lane_ty);
+            assert_eq!(lane_count, ret_lane_count);
+
+            for lane_idx in 0..lane_count {
+                let ptr_lane = ptr.value_lane(fx, lane_idx).load_scalar(fx);
+                let offset_lane = offset.value_lane(fx, lane_idx).load_scalar(fx);
+
+                let ptr_diff = if pointee_size != 1 {
+                    fx.bcx.ins().imul_imm(offset_lane, pointee_size as i64)
+                } else {
+                    offset_lane
+                };
+                let res_lane = fx.bcx.ins().iadd(ptr_lane, ptr_diff);
+                let res_lane = CValue::by_val(res_lane, ret_lane_layout);
+
+                ret.place_lane(fx, lane_idx).write_cvalue(fx, res_lane);
+            }
+        }
+
+        sym::simd_gather => {
+            intrinsic_args!(fx, args => (val, ptr, mask); intrinsic);
+
+            let (val_lane_count, val_lane_ty) = val.layout().ty.simd_size_and_type(fx.tcx);
+            let (ptr_lane_count, _ptr_lane_ty) = ptr.layout().ty.simd_size_and_type(fx.tcx);
+            let (mask_lane_count, _mask_lane_ty) = mask.layout().ty.simd_size_and_type(fx.tcx);
+            let (ret_lane_count, ret_lane_ty) = ret.layout().ty.simd_size_and_type(fx.tcx);
+            assert_eq!(val_lane_count, ptr_lane_count);
+            assert_eq!(val_lane_count, mask_lane_count);
+            assert_eq!(val_lane_count, ret_lane_count);
+
+            let lane_clif_ty = fx.clif_type(val_lane_ty).unwrap();
+            let ret_lane_layout = fx.layout_of(ret_lane_ty);
+
+            for lane_idx in 0..ptr_lane_count {
+                let val_lane = val.value_lane(fx, lane_idx).load_scalar(fx);
+                let ptr_lane = ptr.value_lane(fx, lane_idx).load_scalar(fx);
+                let mask_lane = mask.value_lane(fx, lane_idx).load_scalar(fx);
+
+                let if_enabled = fx.bcx.create_block();
+                let if_disabled = fx.bcx.create_block();
+                let next = fx.bcx.create_block();
+                let res_lane = fx.bcx.append_block_param(next, lane_clif_ty);
+
+                fx.bcx.ins().brnz(mask_lane, if_enabled, &[]);
+                fx.bcx.ins().jump(if_disabled, &[]);
+                fx.bcx.seal_block(if_enabled);
+                fx.bcx.seal_block(if_disabled);
+
+                fx.bcx.switch_to_block(if_enabled);
+                let res = fx.bcx.ins().load(lane_clif_ty, MemFlags::trusted(), ptr_lane, 0);
+                fx.bcx.ins().jump(next, &[res]);
+
+                fx.bcx.switch_to_block(if_disabled);
+                fx.bcx.ins().jump(next, &[val_lane]);
+
+                fx.bcx.seal_block(next);
+                fx.bcx.switch_to_block(next);
+
+                fx.bcx.ins().nop();
+
+                ret.place_lane(fx, lane_idx)
+                    .write_cvalue(fx, CValue::by_val(res_lane, ret_lane_layout));
+            }
+        }
+
+        sym::simd_scatter => {
+            intrinsic_args!(fx, args => (val, ptr, mask); intrinsic);
+
+            let (val_lane_count, _val_lane_ty) = val.layout().ty.simd_size_and_type(fx.tcx);
+            let (ptr_lane_count, _ptr_lane_ty) = ptr.layout().ty.simd_size_and_type(fx.tcx);
+            let (mask_lane_count, _mask_lane_ty) = mask.layout().ty.simd_size_and_type(fx.tcx);
+            assert_eq!(val_lane_count, ptr_lane_count);
+            assert_eq!(val_lane_count, mask_lane_count);
+
+            for lane_idx in 0..ptr_lane_count {
+                let val_lane = val.value_lane(fx, lane_idx).load_scalar(fx);
+                let ptr_lane = ptr.value_lane(fx, lane_idx).load_scalar(fx);
+                let mask_lane = mask.value_lane(fx, lane_idx).load_scalar(fx);
+
+                let if_enabled = fx.bcx.create_block();
+                let next = fx.bcx.create_block();
+
+                fx.bcx.ins().brnz(mask_lane, if_enabled, &[]);
+                fx.bcx.ins().jump(next, &[]);
+                fx.bcx.seal_block(if_enabled);
+
+                fx.bcx.switch_to_block(if_enabled);
+                fx.bcx.ins().store(MemFlags::trusted(), val_lane, ptr_lane, 0);
+                fx.bcx.ins().jump(next, &[]);
+
+                fx.bcx.seal_block(next);
+                fx.bcx.switch_to_block(next);
+            }
+        }
+
         _ => {
-            fx.tcx.sess.span_fatal(span, &format!("Unknown SIMD intrinsic {}", intrinsic));
+            fx.tcx.sess.span_err(span, &format!("Unknown SIMD intrinsic {}", intrinsic));
+            // Prevent verifier error
+            fx.bcx.ins().trap(TrapCode::UnreachableCodeReached);
         }
     }
+    let ret_block = fx.get_block(target);
+    fx.bcx.ins().jump(ret_block, &[]);
 }
index 629d79d501240217d17ac3a6294ff338ed29300c..d3868730557b7e1e4da40a9f684e78be375dcd49 100644 (file)
@@ -57,6 +57,8 @@
 mod concurrency_limiter;
 mod config;
 mod constant;
+// FIXME revert back to the external crate with Cranelift 0.93
+mod cranelift_native;
 mod debuginfo;
 mod discriminant;
 mod driver;
@@ -278,12 +280,14 @@ fn build_isa(sess: &Session, backend_config: &BackendConfig) -> Box<dyn isa::Tar
         }
     }
 
-    if target_triple.architecture == target_lexicon::Architecture::X86_64 {
+    if let target_lexicon::Architecture::Aarch64(_) | target_lexicon::Architecture::X86_64 =
+        target_triple.architecture
+    {
         // Windows depends on stack probes to grow the committed part of the stack
         flags_builder.enable("enable_probestack").unwrap();
         flags_builder.set("probestack_strategy", "inline").unwrap();
     } else {
-        // __cranelift_probestack is not provided and inline stack probes are only supported on x86_64
+        // __cranelift_probestack is not provided and inline stack probes are only supported on AArch64 and x86_64
         flags_builder.set("enable_probestack", "false").unwrap();
     }
 
index c10054e7f0d2c971711364aafdfe563558e3fd5d..fd45362548c0dcc1f5d88ddda1a83c7555e71d70 100644 (file)
@@ -64,13 +64,20 @@ fn create_entry_fn(
             ],
             returns: vec![AbiParam::new(m.target_config().pointer_type() /*isize*/)],
             call_conv: crate::conv_to_call_conv(
+                tcx.sess,
                 tcx.sess.target.options.entry_abi,
                 m.target_config().default_call_conv,
             ),
         };
 
         let entry_name = tcx.sess.target.options.entry_name.as_ref();
-        let cmain_func_id = m.declare_function(entry_name, Linkage::Export, &cmain_sig).unwrap();
+        let cmain_func_id = match m.declare_function(entry_name, Linkage::Export, &cmain_sig) {
+            Ok(func_id) => func_id,
+            Err(err) => {
+                tcx.sess
+                    .fatal(&format!("entry symbol `{entry_name}` declared multiple times: {err}"));
+            }
+        };
 
         let instance = Instance::mono(tcx, rust_main_def_id).polymorphize(tcx);
 
@@ -162,7 +169,11 @@ fn create_entry_fn(
             bcx.seal_all_blocks();
             bcx.finalize();
         }
-        m.define_function(cmain_func_id, &mut ctx).unwrap();
+
+        if let Err(err) = m.define_function(cmain_func_id, &mut ctx) {
+            tcx.sess.fatal(&format!("entry symbol `{entry_name}` defined multiple times: {err}"));
+        }
+
         unwind_context.add_function(cmain_func_id, &ctx, m.isa());
     }
 }
index 7f45bbd8f28136a43b8271ba5f3e2755d19d522d..26327dca299b930da6a973b0683915c4634c78ae 100644 (file)
@@ -7,7 +7,7 @@
 /// otherwise return the given value and false.
 pub(crate) fn maybe_unwrap_bool_not(bcx: &mut FunctionBuilder<'_>, arg: Value) -> (Value, bool) {
     if let ValueDef::Result(arg_inst, 0) = bcx.func.dfg.value_def(arg) {
-        match bcx.func.dfg[arg_inst] {
+        match bcx.func.dfg.insts[arg_inst] {
             // This is the lowering of `Rvalue::Not`
             InstructionData::IntCompareImm {
                 opcode: Opcode::IcmpImm,
@@ -34,7 +34,7 @@ pub(crate) fn maybe_known_branch_taken(
         return None;
     };
 
-    match bcx.func.dfg[arg_inst] {
+    match bcx.func.dfg.insts[arg_inst] {
         InstructionData::UnaryImm { opcode: Opcode::Iconst, imm } => {
             if test_zero {
                 Some(imm.bits() == 0)
index fe8af21ac6de567cff94a34ec13e625f8876fe4a..fa06d6c3ba7f3a2a27b9f14b73d8862cfac75d87 100644 (file)
@@ -514,8 +514,8 @@ fn transmute_value<'tcx>(
                 (types::I32, types::F32)
                 | (types::F32, types::I32)
                 | (types::I64, types::F64)
-                | (types::F64, types::I64) => fx.bcx.ins().bitcast(dst_ty, data),
-                _ if src_ty.is_vector() && dst_ty.is_vector() => fx.bcx.ins().bitcast(dst_ty, data),
+                | (types::F64, types::I64) => codegen_bitcast(fx, dst_ty, data),
+                _ if src_ty.is_vector() && dst_ty.is_vector() => codegen_bitcast(fx, dst_ty, data),
                 _ if src_ty.is_vector() || dst_ty.is_vector() => {
                     // FIXME do something more efficient for transmutes between vectors and integers.
                     let stack_slot = fx.bcx.create_sized_stack_slot(StackSlotData {
index 02e1e21ade1de98f4d72256adbe70755a3997a55..fd825d02e355c0bfd3f58a6a8e99a33806ab33be 100755 (executable)
@@ -3,7 +3,7 @@
 # This block is ignored by rustc
 set -e
 echo "[BUILD] y.rs" 1>&2
-rustc $0 -o ${0/.rs/.bin} -Cdebuginfo=1 --edition 2021
+rustc $0 -o ${0/.rs/.bin} -Cdebuginfo=1 --edition 2021 -Cpanic=abort
 exec ${0/.rs/.bin} $@
 */
 
index a92242b2615c1f66b1cfb438c61a0bbf48ad0e97..e88c12716ecd3d240da161bd05e7c7900067a39b 100644 (file)
@@ -709,7 +709,7 @@ fn scalar_load_metadata<'a, 'gcc, 'tcx>(bx: &mut Builder<'a, 'gcc, 'tcx>, load:
                         bx.range_metadata(load, vr);
                     }
                 }
-                abi::Pointer if vr.start < vr.end && !vr.contains(0) => {
+                abi::Pointer(_) if vr.start < vr.end && !vr.contains(0) => {
                     bx.nonnull_metadata(load);
                 }
                 _ => {}
index 0afc56b4494d3a237948dd508dbd4e5c00bf9cac..c939da9cec3c21346be0ed6b5db214830bb858b1 100644 (file)
@@ -211,7 +211,7 @@ fn scalar_to_backend(&self, cv: Scalar, layout: abi::Scalar, ty: Type<'gcc>) ->
                 let base_addr = self.const_bitcast(base_addr, self.usize_type);
                 let offset = self.context.new_rvalue_from_long(self.usize_type, offset.bytes() as i64);
                 let ptr = self.const_bitcast(base_addr + offset, ptr_type);
-                if layout.primitive() != Pointer {
+                if !matches!(layout.primitive(), Pointer(_)) {
                     self.const_bitcast(ptr.dereference(None).to_rvalue(), ty)
                 }
                 else {
index ea8ab76114604208ed7a9b619dc257e4e9e9c4ff..dc41cb761b59c44b9e60d2567d3b5b5b276a315f 100644 (file)
@@ -322,13 +322,16 @@ pub fn const_alloc_to_gcc<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, alloc: ConstAl
             )
             .expect("const_alloc_to_llvm: could not read relocation pointer")
             as u64;
+
+        let address_space = cx.tcx.global_alloc(alloc_id).address_space(cx);
+
         llvals.push(cx.scalar_to_backend(
             InterpScalar::from_pointer(
                 interpret::Pointer::new(alloc_id, Size::from_bytes(ptr_offset)),
                 &cx.tcx,
             ),
-            abi::Scalar::Initialized { value: Primitive::Pointer, valid_range: WrappingRange::full(dl.pointer_size) },
-            cx.type_i8p(),
+            abi::Scalar::Initialized { value: Primitive::Pointer(address_space), valid_range: WrappingRange::full(dl.pointer_size) },
+            cx.type_i8p_ext(address_space),
         ));
         next_offset = offset + pointer_size;
     }
index 524d10fb5e24d02e52829d96d0b5a970850d1c6e..1326af670cde4e4cc78f3eb1e48eabb79eaf39bb 100644 (file)
@@ -253,7 +253,7 @@ fn scalar_gcc_type_at<'gcc>(&self, cx: &CodegenCx<'gcc, 'tcx>, scalar: &abi::Sca
             Int(i, false) => cx.type_from_unsigned_integer(i),
             F32 => cx.type_f32(),
             F64 => cx.type_f64(),
-            Pointer => {
+            Pointer(address_space) => {
                 // If we know the alignment, pick something better than i8.
                 let pointee =
                     if let Some(pointee) = self.pointee_info_at(cx, offset) {
@@ -262,7 +262,7 @@ fn scalar_gcc_type_at<'gcc>(&self, cx: &CodegenCx<'gcc, 'tcx>, scalar: &abi::Sca
                     else {
                         cx.type_i8()
                     };
-                cx.type_ptr_to(pointee)
+                cx.type_ptr_to_ext(pointee, address_space)
             }
         }
     }
index 52c8b51796c0bf7712e38ddfb44bca2f64c4bdb5..d9f8170a3cffa0617172e93f5d0d5d4a0038efdd 100644 (file)
@@ -849,6 +849,7 @@ fn dummy_output_type<'ll>(cx: &CodegenCx<'ll, '_>, reg: InlineAsmRegClass) -> &'
 /// Helper function to get the LLVM type for a Scalar. Pointers are returned as
 /// the equivalent integer type.
 fn llvm_asm_scalar_type<'ll>(cx: &CodegenCx<'ll, '_>, scalar: Scalar) -> &'ll Type {
+    let dl = &cx.tcx.data_layout;
     match scalar.primitive() {
         Primitive::Int(Integer::I8, _) => cx.type_i8(),
         Primitive::Int(Integer::I16, _) => cx.type_i16(),
@@ -856,7 +857,8 @@ fn llvm_asm_scalar_type<'ll>(cx: &CodegenCx<'ll, '_>, scalar: Scalar) -> &'ll Ty
         Primitive::Int(Integer::I64, _) => cx.type_i64(),
         Primitive::F32 => cx.type_f32(),
         Primitive::F64 => cx.type_f64(),
-        Primitive::Pointer => cx.type_isize(),
+        // FIXME(erikdesjardins): handle non-default addrspace ptr sizes
+        Primitive::Pointer(_) => cx.type_from_integer(dl.ptr_sized_integer()),
         _ => unreachable!(),
     }
 }
@@ -868,6 +870,7 @@ fn llvm_fixup_input<'ll, 'tcx>(
     reg: InlineAsmRegClass,
     layout: &TyAndLayout<'tcx>,
 ) -> &'ll Value {
+    let dl = &bx.tcx.data_layout;
     match (reg, layout.abi) {
         (InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::vreg), Abi::Scalar(s)) => {
             if let Primitive::Int(Integer::I8, _) = s.primitive() {
@@ -881,8 +884,10 @@ fn llvm_fixup_input<'ll, 'tcx>(
             let elem_ty = llvm_asm_scalar_type(bx.cx, s);
             let count = 16 / layout.size.bytes();
             let vec_ty = bx.cx.type_vector(elem_ty, count);
-            if let Primitive::Pointer = s.primitive() {
-                value = bx.ptrtoint(value, bx.cx.type_isize());
+            // FIXME(erikdesjardins): handle non-default addrspace ptr sizes
+            if let Primitive::Pointer(_) = s.primitive() {
+                let t = bx.type_from_integer(dl.ptr_sized_integer());
+                value = bx.ptrtoint(value, t);
             }
             bx.insert_element(bx.const_undef(vec_ty), value, bx.const_i32(0))
         }
@@ -958,7 +963,7 @@ fn llvm_fixup_output<'ll, 'tcx>(
         }
         (InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::vreg_low16), Abi::Scalar(s)) => {
             value = bx.extract_element(value, bx.const_i32(0));
-            if let Primitive::Pointer = s.primitive() {
+            if let Primitive::Pointer(_) = s.primitive() {
                 value = bx.inttoptr(value, layout.llvm_type(bx.cx));
             }
             value
index 5e98deae48aa2dae049de2e28fad05c4df7a256e..0f33b98548984877a230edeb0004e8ba403e7132 100644 (file)
@@ -511,7 +511,7 @@ fn scalar_load_metadata<'a, 'll, 'tcx>(
                         bx.range_metadata(load, scalar.valid_range(bx));
                     }
                 }
-                abi::Pointer => {
+                abi::Pointer(_) => {
                     if !scalar.valid_range(bx).contains(0) {
                         bx.nonnull_metadata(load);
                     }
index acee9134fb96e48a26c3d4eb7a465c8d66ac6bf9..edb1c160626ea7cf3a24b89e9d61541bbd887b17 100644 (file)
@@ -236,7 +236,7 @@ fn scalar_to_backend(&self, cv: Scalar, layout: abi::Scalar, llty: &'ll Type) ->
             Scalar::Int(int) => {
                 let data = int.assert_bits(layout.size(self));
                 let llval = self.const_uint_big(self.type_ix(bitsize), data);
-                if layout.primitive() == Pointer {
+                if matches!(layout.primitive(), Pointer(_)) {
                     unsafe { llvm::LLVMConstIntToPtr(llval, llty) }
                 } else {
                     self.const_bitcast(llval, llty)
@@ -284,7 +284,7 @@ fn scalar_to_backend(&self, cv: Scalar, layout: abi::Scalar, llty: &'ll Type) ->
                         1,
                     )
                 };
-                if layout.primitive() != Pointer {
+                if !matches!(layout.primitive(), Pointer(_)) {
                     unsafe { llvm::LLVMConstPtrToInt(llval, llty) }
                 } else {
                     self.const_bitcast(llval, llty)
index 16467b614feafd3015d192b3734244dee1a6058a..cad3c5d87b73c6bf445a15a08bf8f99702f40e2f 100644 (file)
@@ -13,7 +13,7 @@
 use rustc_hir::def_id::DefId;
 use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs};
 use rustc_middle::mir::interpret::{
-    read_target_uint, Allocation, ConstAllocation, ErrorHandled, GlobalAlloc, InitChunk, Pointer,
+    read_target_uint, Allocation, ConstAllocation, ErrorHandled, InitChunk, Pointer,
     Scalar as InterpScalar,
 };
 use rustc_middle::mir::mono::MonoItem;
@@ -21,9 +21,7 @@
 use rustc_middle::ty::{self, Instance, Ty};
 use rustc_middle::{bug, span_bug};
 use rustc_session::config::Lto;
-use rustc_target::abi::{
-    AddressSpace, Align, HasDataLayout, Primitive, Scalar, Size, WrappingRange,
-};
+use rustc_target::abi::{Align, HasDataLayout, Primitive, Scalar, Size, WrappingRange};
 use std::ops::Range;
 
 pub fn const_alloc_to_llvm<'ll>(cx: &CodegenCx<'ll, '_>, alloc: ConstAllocation<'_>) -> &'ll Value {
@@ -98,12 +96,7 @@ fn append_chunks_of_init_and_uninit_bytes<'ll, 'a, 'b>(
         .expect("const_alloc_to_llvm: could not read relocation pointer")
             as u64;
 
-        let address_space = match cx.tcx.global_alloc(alloc_id) {
-            GlobalAlloc::Function(..) => cx.data_layout().instruction_address_space,
-            GlobalAlloc::Static(..) | GlobalAlloc::Memory(..) | GlobalAlloc::VTable(..) => {
-                AddressSpace::DATA
-            }
-        };
+        let address_space = cx.tcx.global_alloc(alloc_id).address_space(cx);
 
         llvals.push(cx.scalar_to_backend(
             InterpScalar::from_pointer(
@@ -111,7 +104,7 @@ fn append_chunks_of_init_and_uninit_bytes<'ll, 'a, 'b>(
                 &cx.tcx,
             ),
             Scalar::Initialized {
-                value: Primitive::Pointer,
+                value: Primitive::Pointer(address_space),
                 valid_range: WrappingRange::full(dl.pointer_size),
             },
             cx.type_i8p_ext(address_space),
index 22c61248b7d53275fa3e8a662c93ad7f7ae83775..d9a73c7a5c9043fe42934215ee4789e974010fe6 100644 (file)
@@ -1,6 +1,5 @@
 use crate::common::CodegenCx;
 use crate::coverageinfo;
-use crate::errors::InstrumentCoverageRequiresLLVM12;
 use crate::llvm;
 
 use llvm::coverageinfo::CounterMappingRegion;
@@ -19,8 +18,8 @@
 
 /// Generates and exports the Coverage Map.
 ///
-/// Rust Coverage Map generation supports LLVM Coverage Mapping Format versions
-/// 5 (LLVM 12, only) and 6 (zero-based encoded as 4 and 5, respectively), as defined at
+/// Rust Coverage Map generation supports LLVM Coverage Mapping Format version
+/// 6 (zero-based encoded as 5), as defined at
 /// [LLVM Code Coverage Mapping Format](https://github.com/rust-lang/llvm-project/blob/rustc/13.0-2021-09-30/llvm/docs/CoverageMappingFormat.rst#llvm-code-coverage-mapping-format).
 /// These versions are supported by the LLVM coverage tools (`llvm-profdata` and `llvm-cov`)
 /// bundled with Rust's fork of LLVM.
 pub fn finalize(cx: &CodegenCx<'_, '_>) {
     let tcx = cx.tcx;
 
-    // Ensure the installed version of LLVM supports at least Coverage Map
-    // Version 5 (encoded as a zero-based value: 4), which was introduced with
-    // LLVM 12.
+    // Ensure the installed version of LLVM supports Coverage Map Version 6
+    // (encoded as a zero-based value: 5), which was introduced with LLVM 13.
     let version = coverageinfo::mapping_version();
-    if version < 4 {
-        tcx.sess.emit_fatal(InstrumentCoverageRequiresLLVM12);
-    }
+    assert_eq!(version, 5, "The `CoverageMappingVersion` exposed by `llvm-wrapper` is out of sync");
 
     debug!("Generating coverage map for CodegenUnit: `{}`", cx.codegen_unit.name());
 
@@ -61,7 +57,7 @@ pub fn finalize(cx: &CodegenCx<'_, '_>) {
         return;
     }
 
-    let mut mapgen = CoverageMapGenerator::new(tcx, version);
+    let mut mapgen = CoverageMapGenerator::new(tcx);
 
     // Encode coverage mappings and generate function records
     let mut function_data = Vec::new();
@@ -124,25 +120,18 @@ struct CoverageMapGenerator {
 }
 
 impl CoverageMapGenerator {
-    fn new(tcx: TyCtxt<'_>, version: u32) -> Self {
+    fn new(tcx: TyCtxt<'_>) -> Self {
         let mut filenames = FxIndexSet::default();
-        if version >= 5 {
-            // LLVM Coverage Mapping Format version 6 (zero-based encoded as 5)
-            // requires setting the first filename to the compilation directory.
-            // Since rustc generates coverage maps with relative paths, the
-            // compilation directory can be combined with the relative paths
-            // to get absolute paths, if needed.
-            let working_dir = tcx
-                .sess
-                .opts
-                .working_dir
-                .remapped_path_if_available()
-                .to_string_lossy()
-                .to_string();
-            let c_filename =
-                CString::new(working_dir).expect("null error converting filename to C string");
-            filenames.insert(c_filename);
-        }
+        // LLVM Coverage Mapping Format version 6 (zero-based encoded as 5)
+        // requires setting the first filename to the compilation directory.
+        // Since rustc generates coverage maps with relative paths, the
+        // compilation directory can be combined with the relative paths
+        // to get absolute paths, if needed.
+        let working_dir =
+            tcx.sess.opts.working_dir.remapped_path_if_available().to_string_lossy().to_string();
+        let c_filename =
+            CString::new(working_dir).expect("null error converting filename to C string");
+        filenames.insert(c_filename);
         Self { filenames }
     }
 
index 564ab351bd41ffbd0d55ebc3e57f2072d1cda594..54e850f25996b0d1894b038e197480f581ab630e 100644 (file)
@@ -122,7 +122,8 @@ fn tag_base_type<'ll, 'tcx>(
                 Primitive::Int(t, _) => t,
                 Primitive::F32 => Integer::I32,
                 Primitive::F64 => Integer::I64,
-                Primitive::Pointer => {
+                // FIXME(erikdesjardins): handle non-default addrspace ptr sizes
+                Primitive::Pointer(_) => {
                     // If the niche is the NULL value of a reference, then `discr_enum_ty` will be
                     // a RawPtr. CodeView doesn't know what to do with enums whose base type is a
                     // pointer so we fix this up to just be `usize`.
index b46209972421fe894fd4b217013d7072558d6682..001d1ce93d8b479ee6184658373b78504813dab9 100644 (file)
@@ -39,10 +39,6 @@ pub(crate) struct ErrorCreatingImportLibrary<'a> {
     pub error: String,
 }
 
-#[derive(Diagnostic)]
-#[diag(codegen_llvm_instrument_coverage_requires_llvm_12)]
-pub(crate) struct InstrumentCoverageRequiresLLVM12;
-
 #[derive(Diagnostic)]
 #[diag(codegen_llvm_symbol_already_defined)]
 pub(crate) struct SymbolAlreadyDefined<'a> {
index a6a75eff9a36d24e0c331aa3e171f09b3f839ebc..dd89c4c59c14d83e0ac639f5557e628b26ac17ff 100644 (file)
@@ -149,7 +149,7 @@ fn codegen_intrinsic_call(
                                     emit_va_arg(self, args[0], ret_ty)
                                 }
                             }
-                            Primitive::F64 | Primitive::Pointer => {
+                            Primitive::F64 | Primitive::Pointer(_) => {
                                 emit_va_arg(self, args[0], ret_ty)
                             }
                             // `va_arg` should never be used with the return type f32.
index 75cd5df972316366807d06a8d5cfa4d6a399ff0a..c73d233b767a41cb20720ebd1696a7a9ec0f04b0 100644 (file)
@@ -7,7 +7,7 @@
 use rustc_middle::ty::layout::{FnAbiOf, LayoutOf, TyAndLayout};
 use rustc_middle::ty::print::{with_no_trimmed_paths, with_no_visible_paths};
 use rustc_middle::ty::{self, Ty, TypeVisitable};
-use rustc_target::abi::{Abi, AddressSpace, Align, FieldsShape};
+use rustc_target::abi::{Abi, Align, FieldsShape};
 use rustc_target::abi::{Int, Pointer, F32, F64};
 use rustc_target::abi::{PointeeInfo, Scalar, Size, TyAbiInterface, Variants};
 use smallvec::{smallvec, SmallVec};
@@ -312,14 +312,13 @@ fn scalar_llvm_type_at<'a>(
             Int(i, _) => cx.type_from_integer(i),
             F32 => cx.type_f32(),
             F64 => cx.type_f64(),
-            Pointer => {
+            Pointer(address_space) => {
                 // If we know the alignment, pick something better than i8.
-                let (pointee, address_space) =
-                    if let Some(pointee) = self.pointee_info_at(cx, offset) {
-                        (cx.type_pointee_for_align(pointee.align), pointee.address_space)
-                    } else {
-                        (cx.type_i8(), AddressSpace::DATA)
-                    };
+                let pointee = if let Some(pointee) = self.pointee_info_at(cx, offset) {
+                    cx.type_pointee_for_align(pointee.align)
+                } else {
+                    cx.type_i8()
+                };
                 cx.type_ptr_to_ext(pointee, address_space)
             }
         }
index b148e4185a68a795ce5f2c02e8e164dbcee8cada..4ac7bea03ebc01e7a77abcfb8597673e3bf0d3ca 100644 (file)
@@ -599,7 +599,8 @@ fn link_dwarf_object<'a>(
     cg_results: &CodegenResults,
     executable_out_filename: &Path,
 ) {
-    let dwp_out_filename = executable_out_filename.with_extension("dwp");
+    let mut dwp_out_filename = executable_out_filename.to_path_buf().into_os_string();
+    dwp_out_filename.push(".dwp");
     debug!(?dwp_out_filename, ?executable_out_filename);
 
     #[derive(Default)]
@@ -1300,12 +1301,6 @@ fn preserve_objects_for_their_debuginfo(sess: &Session) -> (bool, bool) {
         return (false, false);
     }
 
-    // If we're only producing artifacts that are archives, no need to preserve
-    // the objects as they're losslessly contained inside the archives.
-    if sess.crate_types().iter().all(|&x| x.is_archive()) {
-        return (false, false);
-    }
-
     match (sess.split_debuginfo(), sess.opts.unstable_opts.split_dwarf_kind) {
         // If there is no split debuginfo then do not preserve objects.
         (SplitDebuginfo::Off, _) => (false, false),
index 978aff511bfa74d07f2ecbcc4a20aa3155d2e62d..2848ec1370670b2315c17d7424d17b9165ab4273 100644 (file)
@@ -678,8 +678,8 @@ enum AssertIntrinsic {
             let layout = bx.layout_of(ty);
             let do_panic = match intrinsic {
                 Inhabited => layout.abi.is_uninhabited(),
-                ZeroValid => !bx.tcx().permits_zero_init(layout),
-                MemUninitializedValid => !bx.tcx().permits_uninit_init(layout),
+                ZeroValid => !bx.tcx().permits_zero_init(bx.param_env().and(layout)),
+                MemUninitializedValid => !bx.tcx().permits_uninit_init(bx.param_env().and(layout)),
             };
             Some(if do_panic {
                 let msg_str = with_no_visible_paths!({
@@ -1801,8 +1801,8 @@ fn codegen_transmute_into(
         match (src.layout.abi, dst.layout.abi) {
             (abi::Abi::Scalar(src_scalar), abi::Abi::Scalar(dst_scalar)) => {
                 // HACK(eddyb) LLVM doesn't like `bitcast`s between pointers and non-pointers.
-                let src_is_ptr = src_scalar.primitive() == abi::Pointer;
-                let dst_is_ptr = dst_scalar.primitive() == abi::Pointer;
+                let src_is_ptr = matches!(src_scalar.primitive(), abi::Pointer(_));
+                let dst_is_ptr = matches!(dst_scalar.primitive(), abi::Pointer(_));
                 if src_is_ptr == dst_is_ptr {
                     assert_eq!(src.layout.size, dst.layout.size);
 
index fbe30154a7c8d26b23cb4af4ac5fa419e2a558ad..cf02f59f67b97c3470c281d511ed4ade1390ec84 100644 (file)
@@ -9,7 +9,7 @@
 use rustc_middle::mir::tcx::PlaceTy;
 use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf, TyAndLayout};
 use rustc_middle::ty::{self, Ty};
-use rustc_target::abi::{Abi, Align, FieldsShape, Int, TagEncoding};
+use rustc_target::abi::{Abi, Align, FieldsShape, Int, Pointer, TagEncoding};
 use rustc_target::abi::{VariantIdx, Variants};
 
 #[derive(Copy, Clone, Debug)]
@@ -209,6 +209,7 @@ pub fn codegen_get_discr<Bx: BuilderMethods<'a, 'tcx, Value = V>>(
         bx: &mut Bx,
         cast_to: Ty<'tcx>,
     ) -> V {
+        let dl = &bx.tcx().data_layout;
         let cast_to_layout = bx.cx().layout_of(cast_to);
         let cast_to_size = cast_to_layout.layout.size();
         let cast_to = bx.cx().immediate_backend_type(cast_to_layout);
@@ -250,12 +251,14 @@ pub fn codegen_get_discr<Bx: BuilderMethods<'a, 'tcx, Value = V>>(
             TagEncoding::Niche { untagged_variant, ref niche_variants, niche_start } => {
                 // Cast to an integer so we don't have to treat a pointer as a
                 // special case.
-                let (tag, tag_llty) = if tag_scalar.primitive().is_ptr() {
-                    let t = bx.type_isize();
-                    let tag = bx.ptrtoint(tag_imm, t);
-                    (tag, t)
-                } else {
-                    (tag_imm, bx.cx().immediate_backend_type(tag_op.layout))
+                let (tag, tag_llty) = match tag_scalar.primitive() {
+                    // FIXME(erikdesjardins): handle non-default addrspace ptr sizes
+                    Pointer(_) => {
+                        let t = bx.type_from_integer(dl.ptr_sized_integer());
+                        let tag = bx.ptrtoint(tag_imm, t);
+                        (tag, t)
+                    }
+                    _ => (tag_imm, bx.cx().immediate_backend_type(tag_op.layout)),
                 };
 
                 let tag_size = tag_scalar.size(bx.cx());
index cc7b6c91b607426e57cd6ff9b65b597eb8b4d54e..f87e4fbc1a17809105391a98722d7f881e72e071 100644 (file)
@@ -447,7 +447,7 @@ pub fn emulate_intrinsic(
                 }
 
                 if intrinsic_name == sym::assert_zero_valid {
-                    let should_panic = !self.tcx.permits_zero_init(layout);
+                    let should_panic = !self.tcx.permits_zero_init(self.param_env.and(layout));
 
                     if should_panic {
                         M::abort(
@@ -461,7 +461,7 @@ pub fn emulate_intrinsic(
                 }
 
                 if intrinsic_name == sym::assert_mem_uninitialized_valid {
-                    let should_panic = !self.tcx.permits_uninit_init(layout);
+                    let should_panic = !self.tcx.permits_uninit_init(self.param_env.and(layout));
 
                     if should_panic {
                         M::abort(
index befc0928f3debd253efecb036e95d991b02be214..a1b3985dce4e6ecfa27ff80b225e28e28f1d9d91 100644 (file)
@@ -319,7 +319,7 @@ fn read_immediate_from_mplace_raw(
                 assert_eq!(size, mplace.layout.size, "abi::Scalar size does not match layout size");
                 let scalar = alloc.read_scalar(
                     alloc_range(Size::ZERO, size),
-                    /*read_provenance*/ s.is_ptr(),
+                    /*read_provenance*/ matches!(s, abi::Pointer(_)),
                 )?;
                 Some(ImmTy { imm: scalar.into(), layout: mplace.layout })
             }
@@ -335,11 +335,11 @@ fn read_immediate_from_mplace_raw(
                 assert!(b_offset.bytes() > 0); // in `operand_field` we use the offset to tell apart the fields
                 let a_val = alloc.read_scalar(
                     alloc_range(Size::ZERO, a_size),
-                    /*read_provenance*/ a.is_ptr(),
+                    /*read_provenance*/ matches!(a, abi::Pointer(_)),
                 )?;
                 let b_val = alloc.read_scalar(
                     alloc_range(b_offset, b_size),
-                    /*read_provenance*/ b.is_ptr(),
+                    /*read_provenance*/ matches!(b, abi::Pointer(_)),
                 )?;
                 Some(ImmTy { imm: Immediate::ScalarPair(a_val, b_val), layout: mplace.layout })
             }
index 57b91df2d0708f8f06e35438518c51b6f148df6c..51624a0c6c817bb4a5327cd3cf1e744a75329772 100644 (file)
@@ -58,7 +58,12 @@ pub fn provide(providers: &mut Providers) {
         let (param_env, value) = param_env_and_value.into_parts();
         const_eval::deref_mir_constant(tcx, param_env, value)
     };
-    providers.permits_uninit_init =
-        |tcx, ty| util::might_permit_raw_init(tcx, ty, InitKind::UninitMitigated0x01Fill);
-    providers.permits_zero_init = |tcx, ty| util::might_permit_raw_init(tcx, ty, InitKind::Zero);
+    providers.permits_uninit_init = |tcx, param_env_and_ty| {
+        let (param_env, ty) = param_env_and_ty.into_parts();
+        util::might_permit_raw_init(tcx, param_env, ty, InitKind::UninitMitigated0x01Fill)
+    };
+    providers.permits_zero_init = |tcx, param_env_and_ty| {
+        let (param_env, ty) = param_env_and_ty.into_parts();
+        util::might_permit_raw_init(tcx, param_env, ty, InitKind::Zero)
+    };
 }
index 79f1737e32b21fcabe767b8999d753b5210aaa30..cc40c2566d2e6ad60debca45850e423b9b451425 100644 (file)
@@ -754,12 +754,9 @@ fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location
                         let ocx = ObligationCtxt::new(&infcx);
 
                         let predicates = tcx.predicates_of(callee).instantiate(tcx, substs);
-                        let hir_id = tcx
-                            .hir()
-                            .local_def_id_to_hir_id(self.body.source.def_id().expect_local());
                         let cause = ObligationCause::new(
                             terminator.source_info.span,
-                            hir_id,
+                            self.body.source.def_id().expect_local(),
                             ObligationCauseCode::ItemObligation(callee),
                         );
                         let normalized_predicates = ocx.normalize(&cause, param_env, predicates);
index dd168a9ac3cd3e94078cc20e24fb4c18c4b1b35c..3f83d40755ad8ea49116e5f2fa5cb538206da37d 100644 (file)
@@ -13,7 +13,7 @@
     ProjectionElem, RetagKind, RuntimePhase, Rvalue, SourceScope, Statement, StatementKind,
     Terminator, TerminatorKind, UnOp, START_BLOCK,
 };
-use rustc_middle::ty::{self, InstanceDef, ParamEnv, Ty, TyCtxt, TypeVisitable};
+use rustc_middle::ty::{self, InstanceDef, ParamEnv, Ty, TyCtxt};
 use rustc_mir_dataflow::impls::MaybeStorageLive;
 use rustc_mir_dataflow::storage::always_storage_live_locals;
 use rustc_mir_dataflow::{Analysis, ResultsCursor};
@@ -230,11 +230,6 @@ fn mir_assign_valid_types(&self, src: Ty<'tcx>, dest: Ty<'tcx>) -> bool {
             // Equal types, all is good.
             return true;
         }
-        // Normalization reveals opaque types, but we may be validating MIR while computing
-        // said opaque types, causing cycles.
-        if (src, dest).has_opaque_types() {
-            return true;
-        }
 
         crate::util::is_subtype(self.tcx, self.param_env, src, dest)
     }
index 4ce107ea68d4f0f3869cebe3cce00c706a42f58d..48961b7aac64588486695ddc2ba4b61d4a036117 100644 (file)
 /// to the full uninit check).
 pub fn might_permit_raw_init<'tcx>(
     tcx: TyCtxt<'tcx>,
+    param_env: ParamEnv<'tcx>,
     ty: TyAndLayout<'tcx>,
     kind: InitKind,
 ) -> bool {
     if tcx.sess.opts.unstable_opts.strict_init_checks {
         might_permit_raw_init_strict(ty, tcx, kind)
     } else {
-        let layout_cx = LayoutCx { tcx, param_env: ParamEnv::reveal_all() };
+        let layout_cx = LayoutCx { tcx, param_env };
         might_permit_raw_init_lax(ty, &layout_cx, kind)
     }
 }
index 10e673cd9297bda67fddcec349af9f5657a7eaf5..dda422c6dd07ee60cb67674282b657d053976890 100644 (file)
@@ -139,8 +139,7 @@ pub enum ProcessResult<O, E> {
 #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
 struct ObligationTreeId(usize);
 
-type ObligationTreeIdGenerator =
-    std::iter::Map<std::ops::RangeFrom<usize>, fn(usize) -> ObligationTreeId>;
+type ObligationTreeIdGenerator = impl Iterator<Item = ObligationTreeId>;
 
 pub struct ObligationForest<O: ForestObligation> {
     /// The list of obligations. In between calls to [Self::process_obligations],
index f50ad0137b88aacff80bed38c6e5caeccf54cc11..ccefd6adaf14b6012a614e96368d46b83919a3ad 100644 (file)
@@ -296,9 +296,8 @@ fn run_compiler(
 
             if let Some(ppm) = &sess.opts.pretty {
                 if ppm.needs_ast_map() {
-                    let expanded_crate = queries.expansion()?.borrow().0.clone();
                     queries.global_ctxt()?.enter(|tcx| {
-                        pretty::print_after_hir_lowering(tcx, &*expanded_crate, *ppm);
+                        pretty::print_after_hir_lowering(tcx, *ppm);
                         Ok(())
                     })?;
                 } else {
@@ -328,11 +327,15 @@ fn run_compiler(
                 }
             }
 
-            queries.global_ctxt()?;
+            let mut gctxt = queries.global_ctxt()?;
             if callbacks.after_expansion(compiler, queries) == Compilation::Stop {
                 return early_exit();
             }
 
+            // Make sure the `output_filenames` query is run for its side
+            // effects of writing the dep-info and reporting errors.
+            gctxt.enter(|tcx| tcx.output_filenames(()));
+
             if sess.opts.output_types.contains_key(&OutputType::DepInfo)
                 && sess.opts.output_types.len() == 1
             {
@@ -343,7 +346,7 @@ fn run_compiler(
                 return early_exit();
             }
 
-            queries.global_ctxt()?.enter(|tcx| {
+            gctxt.enter(|tcx| {
                 let result = tcx.analysis(());
                 if sess.opts.unstable_opts.save_analysis {
                     let crate_name = tcx.crate_name(LOCAL_CRATE);
@@ -360,6 +363,8 @@ fn run_compiler(
                 result
             })?;
 
+            drop(gctxt);
+
             if callbacks.after_analysis(compiler, queries) == Compilation::Stop {
                 return early_exit();
             }
index ae3ac8625b1862ca109c1a216329268abc6a6557..022051e008e32cfa192c60e88655f2c6f42670ae 100644 (file)
@@ -403,7 +403,7 @@ pub fn print_after_parsing(sess: &Session, krate: &ast::Crate, ppm: PpMode) {
     write_or_print(&out, sess);
 }
 
-pub fn print_after_hir_lowering<'tcx>(tcx: TyCtxt<'tcx>, krate: &ast::Crate, ppm: PpMode) {
+pub fn print_after_hir_lowering<'tcx>(tcx: TyCtxt<'tcx>, ppm: PpMode) {
     if ppm.needs_analysis() {
         abort_on_err(print_with_analysis(tcx, ppm), tcx.sess);
         return;
@@ -420,7 +420,7 @@ pub fn print_after_hir_lowering<'tcx>(tcx: TyCtxt<'tcx>, krate: &ast::Crate, ppm
                 let parse = &sess.parse_sess;
                 pprust::print_crate(
                     sess.source_map(),
-                    krate,
+                    &tcx.resolver_for_lowering(()).borrow().1,
                     src_name,
                     src,
                     annotation.pp_ann(),
@@ -433,7 +433,7 @@ pub fn print_after_hir_lowering<'tcx>(tcx: TyCtxt<'tcx>, krate: &ast::Crate, ppm
 
         AstTree(PpAstTreeMode::Expanded) => {
             debug!("pretty-printing expanded AST");
-            format!("{krate:#?}")
+            format!("{:#?}", tcx.resolver_for_lowering(()).borrow().1)
         }
 
         Hir(s) => call_with_pp_support_hir(&s, tcx, move |annotation, hir_map| {
index 9e4332c428386ff068dd0a2f49ba859cd3b758d4..0021638c10268c9ce5fcf68c7ffac5d0793d570c 100644 (file)
@@ -123,4 +123,7 @@ borrowck_cannot_move_when_borrowed =
 
 borrowck_opaque_type_non_generic_param =
     expected generic {$kind} parameter, found `{$ty}`
-    .label = this generic parameter must be used with a generic {$kind} parameter
+    .label = {STREQ($ty, "'static") ->
+        [true] cannot use static lifetime; use a bound lifetime instead or remove the lifetime parameter from the opaque type
+        *[other] this generic parameter must be used with a generic {$kind} parameter
+    }
index 860212b051f39c4a8739110e9bf1edf220aa23cf..b82c903290b9a2c10c42db4fcfd036335bbdd8d4 100644 (file)
@@ -11,9 +11,6 @@ codegen_llvm_unknown_ctarget_feature_prefix =
 codegen_llvm_error_creating_import_library =
     Error creating import library for {$lib_name}: {$error}
 
-codegen_llvm_instrument_coverage_requires_llvm_12 =
-    rustc option `-C instrument-coverage` requires LLVM 12 or higher.
-
 codegen_llvm_symbol_already_defined =
     symbol `{$symbol_name}` is already defined
 
index 164d6d26d230d656f0896e69cf8269b9d8845aaa..bcc1d9002dfdebe040e00726a48a8a34dceac576 100644 (file)
@@ -147,8 +147,6 @@ infer_region_explanation = {$pref_kind ->
 }{$desc_kind ->
     *[should_not_happen] [{$desc_kind}]
     [restatic] the static lifetime
-    [reempty] the empty lifetime
-    [reemptyuni] the empty lifetime in universe {$desc_arg}
     [revar] lifetime {$desc_arg}
 
     [as_defined] the lifetime `{$desc_arg}` as defined here
index 224855fff8b56f35a7e02214a87749dd8cc89890..f9bda721df34dcb30830c092aa5dd918691c8b9b 100644 (file)
@@ -299,10 +299,18 @@ mir_build_borrow_of_moved_value = borrow of moved value
     .suggestion = borrow this binding in the pattern to avoid moving the value
 
 mir_build_multiple_mut_borrows = cannot borrow value as mutable more than once at a time
-    .label = first mutable borrow, by `{$name}`, occurs here
-    .mutable_borrow = another mutable borrow, by `{$name_mut}`, occurs here
-    .immutable_borrow = also borrowed as immutable, by `{$name_immut}`, here
-    .moved = also moved into `{$name_moved}` here
+
+mir_build_already_borrowed = cannot borrow value as mutable because it is also borrowed as immutable
+
+mir_build_already_mut_borrowed = cannot borrow value as immutable because it is also borrowed as mutable
+
+mir_build_moved_while_borrowed = cannot move out of value because it is borrowed
+
+mir_build_mutable_borrow = value is mutably borrowed by `{$name}` here
+
+mir_build_borrow = value is borrowed by `{$name}` here
+
+mir_build_moved = value is moved into `{$name}` here
 
 mir_build_union_pattern = cannot use unions in constant patterns
 
index 8f063f5082c9541c249b722fc2f9090ad4046d7b..a3e2002da781c230eff39d72ab2452466bf118e2 100644 (file)
@@ -238,6 +238,7 @@ parse_const_let_mutually_exclusive = `const` and `let` are mutually exclusive
 
 parse_invalid_expression_in_let_else = a `{$operator}` expression cannot be directly assigned in `let...else`
 parse_invalid_curly_in_let_else = right curly brace `{"}"}` before `else` in a `let...else` statement not allowed
+parse_extra_if_in_let_else = remove the `if` if you meant to write a `let...else` statement
 
 parse_compound_assignment_expression_in_let = can't reassign to an uninitialized variable
     .suggestion = initialize the variable
index 91857dd227ddd602bb0eeee9eee8a291faa3ebbc..0c2ab3d08f9dea13d6b1da74a346e231f40c9f6f 100644 (file)
@@ -710,3 +710,24 @@ passes_ignored_derived_impls =
       [one] trait {$trait_list}, but this is
      *[other] traits {$trait_list}, but these are
     } intentionally ignored during dead code analysis
+
+passes_proc_macro_typeerror = mismatched {$kind} signature
+    .label = found {$found}, expected type `proc_macro::TokenStream`
+    .note = {$kind}s must have a signature of `{$expected_signature}`
+
+passes_proc_macro_diff_arg_count = mismatched {$kind} signature
+    .label = found unexpected {$count ->
+      [one] argument
+     *[other] arguments
+    }
+    .note = {$kind}s must have a signature of `{$expected_signature}`
+
+passes_proc_macro_missing_args = mismatched {$kind} signature
+    .label = {$kind} must have {$expected_input_count ->
+      [one] one argument
+     *[other] two arguments
+    } of type `proc_macro::TokenStream`
+
+passes_proc_macro_invalid_abi = proc macro functions may not be `extern "{$abi}"`
+
+passes_proc_macro_unsafe = proc macro functions may not be `unsafe`
index 37a51980a0888b375ff07b9b33fdca744c521337..f053bdc3809be30d5377cae4abc3960f503644b9 100644 (file)
@@ -182,6 +182,9 @@ pub fn fluent_bundle(
     trace!(?locale);
     let mut bundle = new_bundle(vec![locale]);
 
+    // Add convenience functions available to ftl authors.
+    register_functions(&mut bundle);
+
     // Fluent diagnostics can insert directionality isolation markers around interpolated variables
     // indicating that there may be a shift from right-to-left to left-to-right text (or
     // vice-versa). These are disabled because they are sometimes visible in the error output, but
@@ -244,6 +247,15 @@ pub fn fluent_bundle(
     Ok(Some(bundle))
 }
 
+fn register_functions(bundle: &mut FluentBundle) {
+    bundle
+        .add_function("STREQ", |positional, _named| match positional {
+            [FluentValue::String(a), FluentValue::String(b)] => format!("{}", (a == b)).into(),
+            _ => FluentValue::Error,
+        })
+        .expect("Failed to add a function to the bundle.");
+}
+
 /// Type alias for the result of `fallback_fluent_bundle` - a reference-counted pointer to a lazily
 /// evaluated fluent bundle.
 pub type LazyFallbackBundle = Lrc<Lazy<FluentBundle, impl FnOnce() -> FluentBundle>>;
@@ -256,6 +268,9 @@ pub fn fallback_fluent_bundle(
 ) -> LazyFallbackBundle {
     Lrc::new(Lazy::new(move || {
         let mut fallback_bundle = new_bundle(vec![langid!("en-US")]);
+
+        register_functions(&mut fallback_bundle);
+
         // See comment in `fluent_bundle`.
         fallback_bundle.set_use_isolating(with_directionality_markers);
 
index 8e2a13a6c0ab1deed02aecbd473868ad1b65cf4e..93d16716346915119dcf3213c27728293e73e20a 100644 (file)
@@ -83,7 +83,8 @@ impl UnstableFeatures {
     /// Otherwise, only `RUSTC_BOOTSTRAP=1` will work.
     pub fn from_environment(krate: Option<&str>) -> Self {
         // `true` if this is a feature-staged build, i.e., on the beta or stable channel.
-        let disable_unstable_features = option_env!("CFG_DISABLE_UNSTABLE_FEATURES").is_some();
+        let disable_unstable_features =
+            option_env!("CFG_DISABLE_UNSTABLE_FEATURES").map(|s| s != "0").unwrap_or(false);
         // Returns whether `krate` should be counted as unstable
         let is_unstable_crate = |var: &str| {
             krate.map_or(false, |name| var.split(',').any(|new_krate| new_krate == name))
index d6566860f8170a96d25bb96f3d2e08a56c88b6fc..5a620263e4299a2b51fb9f4c032196f22e597534 100644 (file)
@@ -2117,6 +2117,8 @@ pub enum MatchSource {
     TryDesugar,
     /// A desugared `<expr>.await`.
     AwaitDesugar,
+    /// A desugared `format_args!()`.
+    FormatArgs,
 }
 
 impl MatchSource {
@@ -2128,6 +2130,7 @@ pub const fn name(self) -> &'static str {
             ForLoopDesugar => "for",
             TryDesugar => "?",
             AwaitDesugar => ".await",
+            FormatArgs => "format_args!()",
         }
     }
 }
@@ -3524,6 +3527,13 @@ pub fn fn_sig(self) -> Option<&'hir FnSig<'hir>> {
         }
     }
 
+    pub fn alias_ty(self) -> Option<&'hir Ty<'hir>> {
+        match self {
+            Node::Item(Item { kind: ItemKind::TyAlias(ty, ..), .. }) => Some(ty),
+            _ => None,
+        }
+    }
+
     pub fn body_id(&self) -> Option<BodyId> {
         match self {
             Node::TraitItem(TraitItem {
index 54fa5702fbca4b49298e49472722991f023a9751..9158fc082471f8fbedaf7e915fa998d83243215d 100644 (file)
@@ -244,6 +244,14 @@ pub fn extract(attrs: &[ast::Attribute]) -> Option<(Symbol, Span)> {
     /// libstd panic entry point. Necessary for const eval to be able to catch it
     BeginPanic,              sym::begin_panic,         begin_panic_fn,             Target::Fn,             GenericRequirement::None;
 
+    // Lang items needed for `format_args!()`.
+    FormatAlignment,         sym::format_alignment,    format_alignment,           Target::Enum,           GenericRequirement::None;
+    FormatArgument,          sym::format_argument,     format_argument,            Target::Struct,         GenericRequirement::None;
+    FormatArguments,         sym::format_arguments,    format_arguments,           Target::Struct,         GenericRequirement::None;
+    FormatCount,             sym::format_count,        format_count,               Target::Enum,           GenericRequirement::None;
+    FormatPlaceholder,       sym::format_placeholder,  format_placeholder,         Target::Struct,         GenericRequirement::None;
+    FormatUnsafeArg,         sym::format_unsafe_arg,   format_unsafe_arg,          Target::Struct,         GenericRequirement::None;
+
     ExchangeMalloc,          sym::exchange_malloc,     exchange_malloc_fn,         Target::Fn,             GenericRequirement::None;
     BoxFree,                 sym::box_free,            box_free_fn,                Target::Fn,             GenericRequirement::Minimum(1);
     DropInPlace,             sym::drop_in_place,       drop_in_place_fn,           Target::Fn,             GenericRequirement::Minimum(1);
index 730560cc6868627e593dad15649f951df8075093..a5c96a8b01613aa42a51389536b4abfad7b3b0fa 100644 (file)
@@ -2,11 +2,11 @@
 use crate::traits::query::evaluate_obligation::InferCtxtExt;
 use crate::traits::NormalizeExt;
 use crate::traits::{self, TraitEngine, TraitEngineExt};
-use rustc_hir as hir;
 use rustc_infer::infer::InferCtxt;
 use rustc_middle::ty::TypeVisitable;
 use rustc_middle::ty::{self, Ty, TyCtxt};
 use rustc_session::Limit;
+use rustc_span::def_id::LocalDefId;
 use rustc_span::def_id::LOCAL_CRATE;
 use rustc_span::Span;
 
@@ -28,7 +28,7 @@ pub struct Autoderef<'a, 'tcx> {
     // Meta infos:
     infcx: &'a InferCtxt<'tcx>,
     span: Span,
-    body_id: hir::HirId,
+    body_id: LocalDefId,
     param_env: ty::ParamEnv<'tcx>,
 
     // Current state:
@@ -96,14 +96,14 @@ impl<'a, 'tcx> Autoderef<'a, 'tcx> {
     pub fn new(
         infcx: &'a InferCtxt<'tcx>,
         param_env: ty::ParamEnv<'tcx>,
-        body_id: hir::HirId,
+        body_def_id: LocalDefId,
         span: Span,
         base_ty: Ty<'tcx>,
     ) -> Autoderef<'a, 'tcx> {
         Autoderef {
             infcx,
             span,
-            body_id,
+            body_id: body_def_id,
             param_env,
             state: AutoderefSnapshot {
                 steps: vec![],
index abc1c2d7b8d1754ade0e1b977b8032a7c331c787..6c7482b40c3d2f3c30e48237da80113016885884 100644 (file)
@@ -412,7 +412,6 @@ fn check_opaque_meets_bounds<'tcx>(
     span: Span,
     origin: &hir::OpaqueTyOrigin,
 ) {
-    let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
     let defining_use_anchor = match *origin {
         hir::OpaqueTyOrigin::FnReturn(did) | hir::OpaqueTyOrigin::AsyncFn(did) => did,
         hir::OpaqueTyOrigin::TyAlias => def_id,
@@ -438,7 +437,7 @@ fn check_opaque_meets_bounds<'tcx>(
         _ => re,
     });
 
-    let misc_cause = traits::ObligationCause::misc(span, hir_id);
+    let misc_cause = traits::ObligationCause::misc(span, def_id);
 
     match ocx.eq(&misc_cause, param_env, opaque_ty, hidden_ty) {
         Ok(()) => {}
index cfebcceef3cdb1e1096907e76fd6df256d5dbdd5..c09294090d3102094628956b1ca410959fe037bd 100644 (file)
@@ -147,12 +147,12 @@ fn compare_method_predicate_entailment<'tcx>(
     //
     // FIXME(@lcnr): remove that after removing `cause.body_id` from
     // obligations.
-    let impl_m_hir_id = tcx.hir().local_def_id_to_hir_id(impl_m.def_id.expect_local());
+    let impl_m_def_id = impl_m.def_id.expect_local();
     let cause = ObligationCause::new(
         impl_m_span,
-        impl_m_hir_id,
+        impl_m_def_id,
         ObligationCauseCode::CompareImplItemObligation {
-            impl_item_def_id: impl_m.def_id.expect_local(),
+            impl_item_def_id: impl_m_def_id,
             trait_item_def_id: trait_m.def_id,
             kind: impl_m.kind,
         },
@@ -198,7 +198,7 @@ fn compare_method_predicate_entailment<'tcx>(
     // Construct trait parameter environment and then shift it into the placeholder viewpoint.
     // The key step here is to update the caller_bounds's predicates to be
     // the new hybrid bounds we computed.
-    let normalize_cause = traits::ObligationCause::misc(impl_m_span, impl_m_hir_id);
+    let normalize_cause = traits::ObligationCause::misc(impl_m_span, impl_m_def_id);
     let param_env = ty::ParamEnv::new(
         tcx.intern_predicates(&hybrid_preds.predicates),
         Reveal::UserFacing,
@@ -213,14 +213,14 @@ fn compare_method_predicate_entailment<'tcx>(
 
     let impl_m_own_bounds = impl_m_predicates.instantiate_own(tcx, impl_to_placeholder_substs);
     for (predicate, span) in impl_m_own_bounds {
-        let normalize_cause = traits::ObligationCause::misc(span, impl_m_hir_id);
+        let normalize_cause = traits::ObligationCause::misc(span, impl_m_def_id);
         let predicate = ocx.normalize(&normalize_cause, param_env, predicate);
 
         let cause = ObligationCause::new(
             span,
-            impl_m_hir_id,
+            impl_m_def_id,
             ObligationCauseCode::CompareImplItemObligation {
-                impl_item_def_id: impl_m.def_id.expect_local(),
+                impl_item_def_id: impl_m_def_id,
                 trait_item_def_id: trait_m.def_id,
                 kind: impl_m.kind,
             },
@@ -253,7 +253,7 @@ fn compare_method_predicate_entailment<'tcx>(
     );
     let unnormalized_impl_fty = tcx.mk_fn_ptr(ty::Binder::dummy(unnormalized_impl_sig));
 
-    let norm_cause = ObligationCause::misc(impl_m_span, impl_m_hir_id);
+    let norm_cause = ObligationCause::misc(impl_m_span, impl_m_def_id);
     let impl_sig = ocx.normalize(&norm_cause, param_env, unnormalized_impl_sig);
     debug!("compare_impl_method: impl_fty={:?}", impl_sig);
 
@@ -311,6 +311,7 @@ fn compare_method_predicate_entailment<'tcx>(
     if !errors.is_empty() {
         match check_implied_wf {
             CheckImpliedWfMode::Check => {
+                let impl_m_hir_id = tcx.hir().local_def_id_to_hir_id(impl_m_def_id);
                 return compare_method_predicate_entailment(
                     tcx,
                     impl_m,
@@ -336,7 +337,7 @@ fn compare_method_predicate_entailment<'tcx>(
     let outlives_env = OutlivesEnvironment::with_bounds(
         param_env,
         Some(infcx),
-        infcx.implied_bounds_tys(param_env, impl_m_hir_id, wf_tys.clone()),
+        infcx.implied_bounds_tys(param_env, impl_m_def_id, wf_tys.clone()),
     );
     infcx.process_registered_region_obligations(
         outlives_env.region_bound_pairs(),
@@ -346,6 +347,7 @@ fn compare_method_predicate_entailment<'tcx>(
     if !errors.is_empty() {
         // FIXME(compiler-errors): This can be simplified when IMPLIED_BOUNDS_ENTAILMENT
         // becomes a hard error (i.e. ideally we'd just call `resolve_regions_and_report_errors`
+        let impl_m_hir_id = tcx.hir().local_def_id_to_hir_id(impl_m_def_id);
         match check_implied_wf {
             CheckImpliedWfMode::Check => {
                 return compare_method_predicate_entailment(
@@ -371,7 +373,7 @@ fn compare_method_predicate_entailment<'tcx>(
             }
             CheckImpliedWfMode::Skip => {
                 if infcx.tainted_by_errors().is_none() {
-                    infcx.err_ctxt().report_region_errors(impl_m.def_id.expect_local(), &errors);
+                    infcx.err_ctxt().report_region_errors(impl_m_def_id, &errors);
                 }
                 return Err(tcx
                     .sess
@@ -610,13 +612,14 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>(
 
     let trait_to_impl_substs = impl_trait_ref.substs;
 
-    let impl_m_hir_id = tcx.hir().local_def_id_to_hir_id(impl_m.def_id.expect_local());
+    let impl_m_def_id = impl_m.def_id.expect_local();
+    let impl_m_hir_id = tcx.hir().local_def_id_to_hir_id(impl_m_def_id);
     let return_span = tcx.hir().fn_decl_by_hir_id(impl_m_hir_id).unwrap().output.span();
     let cause = ObligationCause::new(
         return_span,
-        impl_m_hir_id,
+        impl_m_def_id,
         ObligationCauseCode::CompareImplItemObligation {
-            impl_item_def_id: impl_m.def_id.expect_local(),
+            impl_item_def_id: impl_m_def_id,
             trait_item_def_id: trait_m.def_id,
             kind: impl_m.kind,
         },
@@ -633,7 +636,7 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>(
     let ocx = ObligationCtxt::new(infcx);
 
     // Normalize the impl signature with fresh variables for lifetime inference.
-    let norm_cause = ObligationCause::misc(return_span, impl_m_hir_id);
+    let norm_cause = ObligationCause::misc(return_span, impl_m_def_id);
     let impl_sig = ocx.normalize(
         &norm_cause,
         param_env,
@@ -650,7 +653,7 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>(
     // the ImplTraitInTraitCollector, which gathers all of the RPITITs and replaces
     // them with inference variables.
     // We will use these inference variables to collect the hidden types of RPITITs.
-    let mut collector = ImplTraitInTraitCollector::new(&ocx, return_span, param_env, impl_m_hir_id);
+    let mut collector = ImplTraitInTraitCollector::new(&ocx, return_span, param_env, impl_m_def_id);
     let unnormalized_trait_sig = tcx
         .liberate_late_bound_regions(
             impl_m.def_id,
@@ -732,12 +735,11 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>(
     let outlives_environment = OutlivesEnvironment::with_bounds(
         param_env,
         Some(infcx),
-        infcx.implied_bounds_tys(param_env, impl_m_hir_id, wf_tys),
+        infcx.implied_bounds_tys(param_env, impl_m_def_id, wf_tys),
     );
-    infcx.err_ctxt().check_region_obligations_and_report_errors(
-        impl_m.def_id.expect_local(),
-        &outlives_environment,
-    )?;
+    infcx
+        .err_ctxt()
+        .check_region_obligations_and_report_errors(impl_m_def_id, &outlives_environment)?;
 
     let mut collected_tys = FxHashMap::default();
     for (def_id, (ty, substs)) in collector.types {
@@ -819,7 +821,7 @@ struct ImplTraitInTraitCollector<'a, 'tcx> {
     types: FxHashMap<DefId, (Ty<'tcx>, ty::SubstsRef<'tcx>)>,
     span: Span,
     param_env: ty::ParamEnv<'tcx>,
-    body_id: hir::HirId,
+    body_id: LocalDefId,
 }
 
 impl<'a, 'tcx> ImplTraitInTraitCollector<'a, 'tcx> {
@@ -827,7 +829,7 @@ fn new(
         ocx: &'a ObligationCtxt<'a, 'tcx>,
         span: Span,
         param_env: ty::ParamEnv<'tcx>,
-        body_id: hir::HirId,
+        body_id: LocalDefId,
     ) -> Self {
         ImplTraitInTraitCollector { ocx, types: FxHashMap::default(), span, param_env, body_id }
     }
@@ -1671,14 +1673,12 @@ pub(super) fn compare_impl_const_raw(
 
     // Create a parameter environment that represents the implementation's
     // method.
-    let impl_c_hir_id = tcx.hir().local_def_id_to_hir_id(impl_const_item_def);
-
     // Compute placeholder form of impl and trait const tys.
     let impl_ty = tcx.type_of(impl_const_item_def.to_def_id());
     let trait_ty = tcx.bound_type_of(trait_const_item_def).subst(tcx, trait_to_impl_substs);
     let mut cause = ObligationCause::new(
         impl_c_span,
-        impl_c_hir_id,
+        impl_const_item_def,
         ObligationCauseCode::CompareImplItemObligation {
             impl_item_def_id: impl_const_item_def,
             trait_item_def_id: trait_const_item_def,
@@ -1799,7 +1799,7 @@ fn compare_type_predicate_entailment<'tcx>(
     // This `HirId` should be used for the `body_id` field on each
     // `ObligationCause` (and the `FnCtxt`). This is what
     // `regionck_item` expects.
-    let impl_ty_hir_id = tcx.hir().local_def_id_to_hir_id(impl_ty.def_id.expect_local());
+    let impl_ty_def_id = impl_ty.def_id.expect_local();
     debug!("compare_type_predicate_entailment: trait_to_impl_substs={:?}", trait_to_impl_substs);
 
     // The predicates declared by the impl definition, the trait and the
@@ -1814,7 +1814,7 @@ fn compare_type_predicate_entailment<'tcx>(
 
     debug!("compare_type_predicate_entailment: bounds={:?}", hybrid_preds);
 
-    let normalize_cause = traits::ObligationCause::misc(impl_ty_span, impl_ty_hir_id);
+    let normalize_cause = traits::ObligationCause::misc(impl_ty_span, impl_ty_def_id);
     let param_env = ty::ParamEnv::new(
         tcx.intern_predicates(&hybrid_preds.predicates),
         Reveal::UserFacing,
@@ -1827,12 +1827,12 @@ fn compare_type_predicate_entailment<'tcx>(
     debug!("compare_type_predicate_entailment: caller_bounds={:?}", param_env.caller_bounds());
 
     for (predicate, span) in impl_ty_own_bounds {
-        let cause = ObligationCause::misc(span, impl_ty_hir_id);
+        let cause = ObligationCause::misc(span, impl_ty_def_id);
         let predicate = ocx.normalize(&cause, param_env, predicate);
 
         let cause = ObligationCause::new(
             span,
-            impl_ty_hir_id,
+            impl_ty_def_id,
             ObligationCauseCode::CompareImplItemObligation {
                 impl_item_def_id: impl_ty.def_id.expect_local(),
                 trait_item_def_id: trait_ty.def_id,
@@ -2008,7 +2008,7 @@ pub(super) fn check_type_bounds<'tcx>(
     };
     debug!(?normalize_param_env);
 
-    let impl_ty_hir_id = tcx.hir().local_def_id_to_hir_id(impl_ty.def_id.expect_local());
+    let impl_ty_def_id = impl_ty.def_id.expect_local();
     let impl_ty_substs = InternalSubsts::identity_for_item(tcx, impl_ty.def_id);
     let rebased_substs = impl_ty_substs.rebase_onto(tcx, container_id, impl_trait_ref.substs);
 
@@ -2020,7 +2020,7 @@ pub(super) fn check_type_bounds<'tcx>(
 
     let normalize_cause = ObligationCause::new(
         impl_ty_span,
-        impl_ty_hir_id,
+        impl_ty_def_id,
         ObligationCauseCode::CheckAssociatedTypeBounds {
             impl_item_def_id: impl_ty.def_id.expect_local(),
             trait_item_def_id: trait_ty.def_id,
@@ -2032,7 +2032,7 @@ pub(super) fn check_type_bounds<'tcx>(
         } else {
             traits::BindingObligation(trait_ty.def_id, span)
         };
-        ObligationCause::new(impl_ty_span, impl_ty_hir_id, code)
+        ObligationCause::new(impl_ty_span, impl_ty_def_id, code)
     };
 
     let obligations = tcx
@@ -2063,7 +2063,7 @@ pub(super) fn check_type_bounds<'tcx>(
 
     // Finally, resolve all regions. This catches wily misuses of
     // lifetime parameters.
-    let implied_bounds = infcx.implied_bounds_tys(param_env, impl_ty_hir_id, assumed_wf_types);
+    let implied_bounds = infcx.implied_bounds_tys(param_env, impl_ty_def_id, assumed_wf_types);
     let outlives_environment =
         OutlivesEnvironment::with_bounds(param_env, Some(&infcx), implied_bounds);
 
index 598dc2dca5c6288b88eab85e96c9f95d0de8fa1b..c93ac5ad963d2faeeaa440a92ad3c4ea29a7ad85 100644 (file)
@@ -56,7 +56,8 @@ fn equate_intrinsic_type<'tcx>(
         && gen_count_ok(own_counts.consts, 0, "const")
     {
         let fty = tcx.mk_fn_ptr(sig);
-        let cause = ObligationCause::new(it.span, it.hir_id(), ObligationCauseCode::IntrinsicType);
+        let it_def_id = it.owner_id.def_id;
+        let cause = ObligationCause::new(it.span, it_def_id, ObligationCauseCode::IntrinsicType);
         require_same_types(tcx, &cause, tcx.mk_fn_ptr(tcx.fn_sig(it.owner_id)), fty);
     }
 }
index 11237afe8a0e36f50b7153370acbe3c20e51b81b..cf14da35375cc0ac7bdcfd5635788649d313a957 100644 (file)
@@ -37,7 +37,7 @@
 pub(super) struct WfCheckingCtxt<'a, 'tcx> {
     pub(super) ocx: ObligationCtxt<'a, 'tcx>,
     span: Span,
-    body_id: hir::HirId,
+    body_def_id: LocalDefId,
     param_env: ty::ParamEnv<'tcx>,
 }
 impl<'a, 'tcx> Deref for WfCheckingCtxt<'a, 'tcx> {
@@ -59,7 +59,7 @@ fn normalize<T>(&self, span: Span, loc: Option<WellFormedLoc>, value: T) -> T
         T: TypeFoldable<'tcx>,
     {
         self.ocx.normalize(
-            &ObligationCause::new(span, self.body_id, ObligationCauseCode::WellFormed(loc)),
+            &ObligationCause::new(span, self.body_def_id, ObligationCauseCode::WellFormed(loc)),
             self.param_env,
             value,
         )
@@ -71,8 +71,11 @@ fn register_wf_obligation(
         loc: Option<WellFormedLoc>,
         arg: ty::GenericArg<'tcx>,
     ) {
-        let cause =
-            traits::ObligationCause::new(span, self.body_id, ObligationCauseCode::WellFormed(loc));
+        let cause = traits::ObligationCause::new(
+            span,
+            self.body_def_id,
+            ObligationCauseCode::WellFormed(loc),
+        );
         // for a type to be WF, we do not need to check if const trait predicates satisfy.
         let param_env = self.param_env.without_const();
         self.ocx.register_obligation(traits::Obligation::new(
@@ -93,11 +96,10 @@ pub(super) fn enter_wf_checking_ctxt<'tcx, F>(
     F: for<'a> FnOnce(&WfCheckingCtxt<'a, 'tcx>),
 {
     let param_env = tcx.param_env(body_def_id);
-    let body_id = tcx.hir().local_def_id_to_hir_id(body_def_id);
     let infcx = &tcx.infer_ctxt().build();
     let ocx = ObligationCtxt::new(infcx);
 
-    let mut wfcx = WfCheckingCtxt { ocx, span, body_id, param_env };
+    let mut wfcx = WfCheckingCtxt { ocx, span, body_def_id, param_env };
 
     if !tcx.features().trivial_bounds {
         wfcx.check_false_global_bounds()
@@ -105,7 +107,7 @@ pub(super) fn enter_wf_checking_ctxt<'tcx, F>(
     f(&mut wfcx);
 
     let assumed_wf_types = wfcx.ocx.assumed_wf_types(param_env, span, body_def_id);
-    let implied_bounds = infcx.implied_bounds_tys(param_env, body_id, assumed_wf_types);
+    let implied_bounds = infcx.implied_bounds_tys(param_env, body_def_id, assumed_wf_types);
 
     let errors = wfcx.select_all_or_error();
     if !errors.is_empty() {
@@ -374,7 +376,6 @@ fn check_gat_where_clauses(tcx: TyCtxt<'_>, associated_items: &[hir::TraitItemRe
                     continue;
                 }
 
-                let item_hir_id = item.id.hir_id();
                 let param_env = tcx.param_env(item_def_id);
 
                 let item_required_bounds = match item.kind {
@@ -390,7 +391,7 @@ fn check_gat_where_clauses(tcx: TyCtxt<'_>, associated_items: &[hir::TraitItemRe
                         gather_gat_bounds(
                             tcx,
                             param_env,
-                            item_hir_id,
+                            item_def_id.def_id,
                             sig.inputs_and_output,
                             // We also assume that all of the function signature's parameter types
                             // are well formed.
@@ -412,7 +413,7 @@ fn check_gat_where_clauses(tcx: TyCtxt<'_>, associated_items: &[hir::TraitItemRe
                         gather_gat_bounds(
                             tcx,
                             param_env,
-                            item_hir_id,
+                            item_def_id.def_id,
                             tcx.explicit_item_bounds(item_def_id).to_vec(),
                             &FxIndexSet::default(),
                             gat_def_id.def_id,
@@ -458,7 +459,6 @@ fn check_gat_where_clauses(tcx: TyCtxt<'_>, associated_items: &[hir::TraitItemRe
         let gat_item_hir = tcx.hir().expect_trait_item(gat_def_id.def_id);
         debug!(?required_bounds);
         let param_env = tcx.param_env(gat_def_id);
-        let gat_hir = gat_item_hir.hir_id();
 
         let mut unsatisfied_bounds: Vec<_> = required_bounds
             .into_iter()
@@ -466,13 +466,25 @@ fn check_gat_where_clauses(tcx: TyCtxt<'_>, associated_items: &[hir::TraitItemRe
                 ty::PredicateKind::Clause(ty::Clause::RegionOutlives(ty::OutlivesPredicate(
                     a,
                     b,
-                ))) => {
-                    !region_known_to_outlive(tcx, gat_hir, param_env, &FxIndexSet::default(), a, b)
-                }
+                ))) => !region_known_to_outlive(
+                    tcx,
+                    gat_def_id.def_id,
+                    param_env,
+                    &FxIndexSet::default(),
+                    a,
+                    b,
+                ),
                 ty::PredicateKind::Clause(ty::Clause::TypeOutlives(ty::OutlivesPredicate(
                     a,
                     b,
-                ))) => !ty_known_to_outlive(tcx, gat_hir, param_env, &FxIndexSet::default(), a, b),
+                ))) => !ty_known_to_outlive(
+                    tcx,
+                    gat_def_id.def_id,
+                    param_env,
+                    &FxIndexSet::default(),
+                    a,
+                    b,
+                ),
                 _ => bug!("Unexpected PredicateKind"),
             })
             .map(|clause| clause.to_string())
@@ -551,7 +563,7 @@ fn augment_param_env<'tcx>(
 fn gather_gat_bounds<'tcx, T: TypeFoldable<'tcx>>(
     tcx: TyCtxt<'tcx>,
     param_env: ty::ParamEnv<'tcx>,
-    item_hir: hir::HirId,
+    item_def_id: LocalDefId,
     to_check: T,
     wf_tys: &FxIndexSet<Ty<'tcx>>,
     gat_def_id: LocalDefId,
@@ -584,7 +596,7 @@ fn gather_gat_bounds<'tcx, T: TypeFoldable<'tcx>>(
         // reflected in a where clause on the GAT itself.
         for (ty, ty_idx) in &types {
             // In our example, requires that `Self: 'a`
-            if ty_known_to_outlive(tcx, item_hir, param_env, &wf_tys, *ty, *region_a) {
+            if ty_known_to_outlive(tcx, item_def_id, param_env, &wf_tys, *ty, *region_a) {
                 debug!(?ty_idx, ?region_a_idx);
                 debug!("required clause: {ty} must outlive {region_a}");
                 // Translate into the generic parameters of the GAT. In
@@ -622,7 +634,7 @@ fn gather_gat_bounds<'tcx, T: TypeFoldable<'tcx>>(
             if ty::ReStatic == **region_b || region_a == region_b {
                 continue;
             }
-            if region_known_to_outlive(tcx, item_hir, param_env, &wf_tys, *region_a, *region_b) {
+            if region_known_to_outlive(tcx, item_def_id, param_env, &wf_tys, *region_a, *region_b) {
                 debug!(?region_a_idx, ?region_b_idx);
                 debug!("required clause: {region_a} must outlive {region_b}");
                 // Translate into the generic parameters of the GAT.
@@ -658,7 +670,7 @@ fn gather_gat_bounds<'tcx, T: TypeFoldable<'tcx>>(
 /// `ty` outlives `region`.
 fn ty_known_to_outlive<'tcx>(
     tcx: TyCtxt<'tcx>,
-    id: hir::HirId,
+    id: LocalDefId,
     param_env: ty::ParamEnv<'tcx>,
     wf_tys: &FxIndexSet<Ty<'tcx>>,
     ty: Ty<'tcx>,
@@ -675,7 +687,7 @@ fn ty_known_to_outlive<'tcx>(
 /// `region_a` outlives `region_b`
 fn region_known_to_outlive<'tcx>(
     tcx: TyCtxt<'tcx>,
-    id: hir::HirId,
+    id: LocalDefId,
     param_env: ty::ParamEnv<'tcx>,
     wf_tys: &FxIndexSet<Ty<'tcx>>,
     region_a: ty::Region<'tcx>,
@@ -699,7 +711,7 @@ fn region_known_to_outlive<'tcx>(
 /// to be tested), then resolve region and return errors
 fn resolve_regions_with_wf_tys<'tcx>(
     tcx: TyCtxt<'tcx>,
-    id: hir::HirId,
+    id: LocalDefId,
     param_env: ty::ParamEnv<'tcx>,
     wf_tys: &FxIndexSet<Ty<'tcx>>,
     add_constraints: impl for<'a> FnOnce(&'a InferCtxt<'tcx>, &'a RegionBoundPairs<'tcx>),
@@ -1093,7 +1105,7 @@ fn check_type_defn<'tcx>(tcx: TyCtxt<'tcx>, item: &hir::Item<'tcx>, all_sized: b
                 wfcx.register_bound(
                     traits::ObligationCause::new(
                         hir_ty.span,
-                        wfcx.body_id,
+                        wfcx.body_def_id,
                         traits::FieldSized {
                             adt_kind: match item_adt_kind(&item.kind) {
                                 Some(i) => i,
@@ -1113,7 +1125,7 @@ fn check_type_defn<'tcx>(tcx: TyCtxt<'tcx>, item: &hir::Item<'tcx>, all_sized: b
             if let ty::VariantDiscr::Explicit(discr_def_id) = variant.discr {
                 let cause = traits::ObligationCause::new(
                     tcx.def_span(discr_def_id),
-                    wfcx.body_id,
+                    wfcx.body_def_id,
                     traits::MiscObligation,
                 );
                 wfcx.register_obligation(traits::Obligation::new(
@@ -1174,7 +1186,7 @@ fn check_associated_type_bounds(wfcx: &WfCheckingCtxt<'_, '_>, item: &ty::AssocI
         traits::wf::predicate_obligations(
             wfcx.infcx,
             wfcx.param_env,
-            wfcx.body_id,
+            wfcx.body_def_id,
             normalized_bound,
             bound_span,
         )
@@ -1214,7 +1226,7 @@ fn check_item_type(tcx: TyCtxt<'_>, item_id: LocalDefId, ty_span: Span, allow_fo
         wfcx.register_wf_obligation(ty_span, Some(WellFormedLoc::Ty(item_id)), item_ty.into());
         if forbid_unsized {
             wfcx.register_bound(
-                traits::ObligationCause::new(ty_span, wfcx.body_id, traits::WellFormed(None)),
+                traits::ObligationCause::new(ty_span, wfcx.body_def_id, traits::WellFormed(None)),
                 wfcx.param_env,
                 item_ty,
                 tcx.require_lang_item(LangItem::Sized, None),
@@ -1229,7 +1241,7 @@ fn check_item_type(tcx: TyCtxt<'_>, item_id: LocalDefId, ty_span: Span, allow_fo
 
         if should_check_for_sync {
             wfcx.register_bound(
-                traits::ObligationCause::new(ty_span, wfcx.body_id, traits::SharedStatic),
+                traits::ObligationCause::new(ty_span, wfcx.body_def_id, traits::SharedStatic),
                 wfcx.param_env,
                 item_ty,
                 tcx.require_lang_item(LangItem::Sync, Some(ty_span)),
@@ -1269,7 +1281,7 @@ fn check_impl<'tcx>(
                 let mut obligations = traits::wf::trait_obligations(
                     wfcx.infcx,
                     wfcx.param_env,
-                    wfcx.body_id,
+                    wfcx.body_def_id,
                     &trait_pred,
                     ast_trait_ref.path.span,
                     item,
@@ -1466,7 +1478,7 @@ fn visit_const(&mut self, c: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
             let pred = wfcx.normalize(sp, None, pred);
             let cause = traits::ObligationCause::new(
                 sp,
-                wfcx.body_id,
+                wfcx.body_def_id,
                 traits::ItemObligation(def_id.to_def_id()),
             );
             traits::Obligation::new(tcx, cause, wfcx.param_env, pred)
@@ -1482,12 +1494,11 @@ fn visit_const(&mut self, c: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
         traits::wf::predicate_obligations(
             infcx,
             wfcx.param_env.without_const(),
-            wfcx.body_id,
+            wfcx.body_def_id,
             p,
             sp,
         )
     });
-
     let obligations: Vec<_> = wf_obligations.chain(default_obligations).collect();
     wfcx.register_obligations(obligations);
 }
@@ -1549,7 +1560,7 @@ fn check_fn_or_method<'tcx>(
         // Check that the argument is a tuple
         if let Some(ty) = inputs.next() {
             wfcx.register_bound(
-                ObligationCause::new(span, wfcx.body_id, ObligationCauseCode::RustCall),
+                ObligationCause::new(span, wfcx.body_def_id, ObligationCauseCode::RustCall),
                 wfcx.param_env,
                 *ty,
                 tcx.require_lang_item(hir::LangItem::Tuple, Some(span)),
@@ -1597,7 +1608,7 @@ fn check_return_position_impl_trait_in_trait_bounds<'tcx>(
                     traits::wf::predicate_obligations(
                         wfcx.infcx,
                         wfcx.param_env,
-                        wfcx.body_id,
+                        wfcx.body_def_id,
                         normalized_bound,
                         bound_span,
                     )
@@ -1697,7 +1708,7 @@ fn receiver_is_valid<'tcx>(
     let infcx = wfcx.infcx;
     let tcx = wfcx.tcx();
     let cause =
-        ObligationCause::new(span, wfcx.body_id, traits::ObligationCauseCode::MethodReceiver);
+        ObligationCause::new(span, wfcx.body_def_id, traits::ObligationCauseCode::MethodReceiver);
 
     let can_eq_self = |ty| infcx.can_eq(wfcx.param_env, self_ty, ty).is_ok();
 
@@ -1709,7 +1720,7 @@ fn receiver_is_valid<'tcx>(
         return true;
     }
 
-    let mut autoderef = Autoderef::new(infcx, wfcx.param_env, wfcx.body_id, span, receiver_ty);
+    let mut autoderef = Autoderef::new(infcx, wfcx.param_env, wfcx.body_def_id, span, receiver_ty);
 
     // The `arbitrary_self_types` feature allows raw pointer receivers like `self: *const Self`.
     if arbitrary_self_types_enabled {
@@ -1894,8 +1905,7 @@ fn check_false_global_bounds(&mut self) {
         let mut span = self.span;
         let empty_env = ty::ParamEnv::empty();
 
-        let def_id = tcx.hir().local_def_id(self.body_id);
-        let predicates_with_span = tcx.predicates_of(def_id).predicates.iter().copied();
+        let predicates_with_span = tcx.predicates_of(self.body_def_id).predicates.iter().copied();
         // Check elaborated bounds.
         let implied_obligations = traits::elaborate_predicates_with_span(tcx, predicates_with_span);
 
@@ -1910,7 +1920,7 @@ fn check_false_global_bounds(&mut self) {
             // Match the existing behavior.
             if pred.is_global() && !pred.has_late_bound_vars() {
                 let pred = self.normalize(span, None, pred);
-                let hir_node = tcx.hir().find(self.body_id);
+                let hir_node = tcx.hir().find_by_def_id(self.body_def_id);
 
                 // only use the span of the predicate clause (#90869)
 
@@ -1929,7 +1939,7 @@ fn check_false_global_bounds(&mut self) {
 
                 let obligation = traits::Obligation::new(
                     tcx,
-                    traits::ObligationCause::new(span, self.body_id, traits::TrivialBound),
+                    traits::ObligationCause::new(span, self.body_def_id, traits::TrivialBound),
                     empty_env,
                     pred,
                 );
index 28c04087868a7d35e4677488297a5ebe865eed6f..76668f7e9ac4b0379a5ff9db80e6a20ebe42e003 100644 (file)
@@ -64,8 +64,6 @@ fn visit_implementation_of_drop(tcx: TyCtxt<'_>, impl_did: LocalDefId) {
 fn visit_implementation_of_copy(tcx: TyCtxt<'_>, impl_did: LocalDefId) {
     debug!("visit_implementation_of_copy: impl_did={:?}", impl_did);
 
-    let impl_hir_id = tcx.hir().local_def_id_to_hir_id(impl_did);
-
     let self_type = tcx.type_of(impl_did);
     debug!("visit_implementation_of_copy: self_type={:?} (bound)", self_type);
 
@@ -80,7 +78,7 @@ fn visit_implementation_of_copy(tcx: TyCtxt<'_>, impl_did: LocalDefId) {
         _ => bug!("expected Copy impl item"),
     };
 
-    let cause = traits::ObligationCause::misc(span, impl_hir_id);
+    let cause = traits::ObligationCause::misc(span, impl_did);
     match type_allowed_to_implement_copy(tcx, param_env, self_type, cause) {
         Ok(()) => {}
         Err(CopyImplementationError::InfrigingFields(fields)) => {
@@ -224,7 +222,7 @@ fn visit_implementation_of_dispatch_from_dyn(tcx: TyCtxt<'_>, impl_did: LocalDef
     let create_err = |msg: &str| struct_span_err!(tcx.sess, span, E0378, "{}", msg);
 
     let infcx = tcx.infer_ctxt().build();
-    let cause = ObligationCause::misc(span, impl_hir_id);
+    let cause = ObligationCause::misc(span, impl_did);
 
     use rustc_type_ir::sty::TyKind::*;
     match (source.kind(), target.kind()) {
@@ -386,8 +384,7 @@ pub fn coerce_unsized_info<'tcx>(tcx: TyCtxt<'tcx>, impl_did: DefId) -> CoerceUn
     debug!("visit_implementation_of_coerce_unsized: {:?} -> {:?} (free)", source, target);
 
     let infcx = tcx.infer_ctxt().build();
-    let impl_hir_id = tcx.hir().local_def_id_to_hir_id(impl_did);
-    let cause = ObligationCause::misc(span, impl_hir_id);
+    let cause = ObligationCause::misc(span, impl_did);
     let check_mutbl = |mt_a: ty::TypeAndMut<'tcx>,
                        mt_b: ty::TypeAndMut<'tcx>,
                        mk_ptr: &dyn Fn(Ty<'tcx>) -> Ty<'tcx>| {
@@ -575,7 +572,7 @@ pub fn coerce_unsized_info<'tcx>(tcx: TyCtxt<'tcx>, impl_did: DefId) -> CoerceUn
     };
 
     // Register an obligation for `A: Trait<B>`.
-    let cause = traits::ObligationCause::misc(span, impl_hir_id);
+    let cause = traits::ObligationCause::misc(span, impl_did);
     let predicate =
         predicate_for_trait_def(tcx, param_env, cause, trait_def_id, 0, [source, target]);
     let errors = traits::fully_solve_obligation(&infcx, predicate);
index c17778ce8bc090e934b82b8399a5d05aa501ac22..e253459ef64ab07d6df9f87193f174215cb93b10 100644 (file)
@@ -1248,11 +1248,12 @@ fn infer_return_ty_for_fn_sig<'tcx>(
     }
 }
 
+// FIXME(vincenzopalazzo): remove the hir item when the refactoring is stable
 fn suggest_impl_trait<'tcx>(
     tcx: TyCtxt<'tcx>,
     ret_ty: Ty<'tcx>,
     span: Span,
-    hir_id: hir::HirId,
+    _hir_id: hir::HirId,
     def_id: LocalDefId,
 ) -> Option<String> {
     let format_as_assoc: fn(_, _, _, _, _) -> _ =
@@ -1324,7 +1325,7 @@ fn suggest_impl_trait<'tcx>(
         }
         let ocx = ObligationCtxt::new_in_snapshot(&infcx);
         let item_ty = ocx.normalize(
-            &ObligationCause::misc(span, hir_id),
+            &ObligationCause::misc(span, def_id),
             param_env,
             tcx.mk_projection(assoc_item_def_id, substs),
         );
index 17dbb126bd1b0f357ac0f0204d8a6d70614cc0ba..9cf82b39ec947b9e4d5ee29e803dfe2fc5a088b6 100644 (file)
@@ -1,11 +1,12 @@
 use crate::collect::ItemCtxt;
 use rustc_hir as hir;
 use rustc_hir::intravisit::{self, Visitor};
-use rustc_hir::{ForeignItem, ForeignItemKind, HirId};
+use rustc_hir::{ForeignItem, ForeignItemKind};
 use rustc_infer::infer::TyCtxtInferExt;
 use rustc_infer::traits::{ObligationCause, WellFormedLoc};
 use rustc_middle::ty::query::Providers;
 use rustc_middle::ty::{self, Region, TyCtxt, TypeFoldable, TypeFolder};
+use rustc_span::def_id::LocalDefId;
 use rustc_trait_selection::traits;
 
 pub fn provide(providers: &mut Providers) {
@@ -57,7 +58,7 @@ struct HirWfCheck<'tcx> {
         cause: Option<ObligationCause<'tcx>>,
         cause_depth: usize,
         icx: ItemCtxt<'tcx>,
-        hir_id: HirId,
+        def_id: LocalDefId,
         param_env: ty::ParamEnv<'tcx>,
         depth: usize,
     }
@@ -68,7 +69,7 @@ fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) {
             let tcx_ty = self.icx.to_ty(ty).fold_with(&mut EraseAllBoundRegions { tcx: self.tcx });
             let cause = traits::ObligationCause::new(
                 ty.span,
-                self.hir_id,
+                self.def_id,
                 traits::ObligationCauseCode::WellFormed(None),
             );
             let errors = traits::fully_solve_obligation(
@@ -106,7 +107,7 @@ fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) {
         cause: None,
         cause_depth: 0,
         icx,
-        hir_id,
+        def_id,
         param_env: tcx.param_env(def_id.to_def_id()),
         depth: 0,
     };
index bcda26c4cc854156c2c7ed4fdfa75d8e1e95a2e7..a5dcfab9be8e84d102923a58822f232df27731e8 100644 (file)
@@ -164,7 +164,6 @@ fn get_impl_substs(
     let infcx = &tcx.infer_ctxt().build();
     let ocx = ObligationCtxt::new(infcx);
     let param_env = tcx.param_env(impl1_def_id);
-    let impl1_hir_id = tcx.hir().local_def_id_to_hir_id(impl1_def_id);
 
     let assumed_wf_types =
         ocx.assumed_wf_types(param_env, tcx.def_span(impl1_def_id), impl1_def_id);
@@ -179,7 +178,7 @@ fn get_impl_substs(
         return None;
     }
 
-    let implied_bounds = infcx.implied_bounds_tys(param_env, impl1_hir_id, assumed_wf_types);
+    let implied_bounds = infcx.implied_bounds_tys(param_env, impl1_def_id, assumed_wf_types);
     let outlives_env = OutlivesEnvironment::with_bounds(param_env, Some(infcx), implied_bounds);
     let _ =
         infcx.err_ctxt().check_region_obligations_and_report_errors(impl1_def_id, &outlives_env);
@@ -372,15 +371,9 @@ fn check_predicates<'tcx>(
     // Include the well-formed predicates of the type parameters of the impl.
     for arg in tcx.impl_trait_ref(impl1_def_id).unwrap().subst_identity().substs {
         let infcx = &tcx.infer_ctxt().build();
-        let obligations = wf::obligations(
-            infcx,
-            tcx.param_env(impl1_def_id),
-            tcx.hir().local_def_id_to_hir_id(impl1_def_id),
-            0,
-            arg,
-            span,
-        )
-        .unwrap();
+        let obligations =
+            wf::obligations(infcx, tcx.param_env(impl1_def_id), impl1_def_id, 0, arg, span)
+                .unwrap();
 
         assert!(!obligations.needs_infer());
         impl2_predicates.extend(
index 02548ae893f28682a16ed0d5593c3f6e642ab524..da35210023891ab37a378a4a55775228af3d4a7b 100644 (file)
 
 use rustc_errors::{struct_span_err, ErrorGuaranteed};
 use rustc_hir as hir;
-use rustc_hir::def_id::DefId;
-use rustc_hir::{Node, CRATE_HIR_ID};
+use rustc_hir::Node;
 use rustc_infer::infer::{InferOk, TyCtxtInferExt};
 use rustc_middle::middle;
 use rustc_middle::ty::query::Providers;
 use rustc_middle::ty::{self, Ty, TyCtxt};
 use rustc_middle::util;
 use rustc_session::{config::EntryFnType, parse::feature_err};
+use rustc_span::def_id::{DefId, LocalDefId, CRATE_DEF_ID};
 use rustc_span::{symbol::sym, Span, DUMMY_SP};
 use rustc_target::spec::abi::Abi;
 use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt as _;
@@ -185,16 +185,15 @@ fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: DefId) {
     let main_fnsig = tcx.fn_sig(main_def_id);
     let main_span = tcx.def_span(main_def_id);
 
-    fn main_fn_diagnostics_hir_id(tcx: TyCtxt<'_>, def_id: DefId, sp: Span) -> hir::HirId {
+    fn main_fn_diagnostics_def_id(tcx: TyCtxt<'_>, def_id: DefId, sp: Span) -> LocalDefId {
         if let Some(local_def_id) = def_id.as_local() {
-            let hir_id = tcx.hir().local_def_id_to_hir_id(local_def_id);
             let hir_type = tcx.type_of(local_def_id);
             if !matches!(hir_type.kind(), ty::FnDef(..)) {
                 span_bug!(sp, "main has a non-function type: found `{}`", hir_type);
             }
-            hir_id
+            local_def_id
         } else {
-            CRATE_HIR_ID
+            CRATE_DEF_ID
         }
     }
 
@@ -251,7 +250,7 @@ fn main_fn_return_type_span(tcx: TyCtxt<'_>, def_id: DefId) -> Option<Span> {
     }
 
     let mut error = false;
-    let main_diagnostics_hir_id = main_fn_diagnostics_hir_id(tcx, main_def_id, main_span);
+    let main_diagnostics_def_id = main_fn_diagnostics_def_id(tcx, main_def_id, main_span);
     let main_fn_generics = tcx.generics_of(main_def_id);
     let main_fn_predicates = tcx.predicates_of(main_def_id);
     if main_fn_generics.count() != 0 || !main_fnsig.bound_vars().is_empty() {
@@ -326,7 +325,7 @@ fn main_fn_return_type_span(tcx: TyCtxt<'_>, def_id: DefId) -> Option<Span> {
         let param_env = ty::ParamEnv::empty();
         let cause = traits::ObligationCause::new(
             return_ty_span,
-            main_diagnostics_hir_id,
+            main_diagnostics_def_id,
             ObligationCauseCode::MainFunctionType,
         );
         let ocx = traits::ObligationCtxt::new(&infcx);
@@ -356,7 +355,7 @@ fn main_fn_return_type_span(tcx: TyCtxt<'_>, def_id: DefId) -> Option<Span> {
         tcx,
         &ObligationCause::new(
             main_span,
-            main_diagnostics_hir_id,
+            main_diagnostics_def_id,
             ObligationCauseCode::MainFunctionType,
         ),
         se_ty,
@@ -444,7 +443,11 @@ fn check_start_fn_ty(tcx: TyCtxt<'_>, start_def_id: DefId) {
 
             require_same_types(
                 tcx,
-                &ObligationCause::new(start_span, start_id, ObligationCauseCode::StartFunctionType),
+                &ObligationCause::new(
+                    start_span,
+                    start_def_id,
+                    ObligationCauseCode::StartFunctionType,
+                ),
                 se_ty,
                 tcx.mk_fn_ptr(tcx.fn_sig(start_def_id)),
             );
index b6f19d3cc684ae1d84fc97b0c1f3fd390af54975..73aba2780d680388e6496981672e40da59fe2529 100644 (file)
@@ -186,10 +186,10 @@ fn suggest_removing_semicolon_for_coerce(
         prior_arm: Option<(Option<hir::HirId>, Ty<'tcx>, Span)>,
     ) {
         let hir = self.tcx.hir();
-
         // First, check that we're actually in the tail of a function.
-        let hir::Node::Expr(hir::Expr { kind: hir::ExprKind::Block(block, _), .. }) =
-            hir.get(self.body_id) else { return; };
+        let Some(body_id) = hir.maybe_body_owned_by(self.body_id) else { return; };
+        let body = hir.body(body_id);
+        let hir::ExprKind::Block(block, _) = body.value.kind else { return; };
         let Some(hir::Stmt { kind: hir::StmtKind::Semi(last_expr), .. })
             = block.innermost_block().stmts.last() else {  return; };
         if last_expr.hir_id != expr.hir_id {
@@ -198,7 +198,7 @@ fn suggest_removing_semicolon_for_coerce(
 
         // Next, make sure that we have no type expectation.
         let Some(ret) = hir
-            .find_by_def_id(self.body_id.owner.def_id)
+            .find_by_def_id(self.body_id)
             .and_then(|owner| owner.fn_decl())
             .map(|decl| decl.output.span()) else { return; };
         let Expectation::IsLast(stmt) = expectation else {
index 57feefbcab6c8cc25b246e313fbf2fbd39f2dced..8bbbf04c0cd4729019ba1fdf6bd7754f3280bed5 100644 (file)
@@ -43,7 +43,7 @@ pub(super) fn check_fn<'a, 'tcx>(
     let ret_ty =
         fcx.register_infer_ok_obligations(fcx.infcx.replace_opaque_types_with_inference_vars(
             declared_ret_ty,
-            body.value.hir_id,
+            fn_def_id,
             decl.output.span(),
             fcx.param_env,
         ));
index 12a2abfa76a921d5402860d134f10c68ad8805ce..329b69eff54a396338f6e6f4e58e69f0ffc3c61c 100644 (file)
@@ -4,7 +4,6 @@
 
 use hir::def::DefKind;
 use rustc_hir as hir;
-use rustc_hir::def_id::LocalDefId;
 use rustc_hir::lang_items::LangItem;
 use rustc_hir_analysis::astconv::AstConv;
 use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
@@ -14,6 +13,7 @@
 use rustc_middle::ty::subst::InternalSubsts;
 use rustc_middle::ty::visit::TypeVisitable;
 use rustc_middle::ty::{self, Ty, TypeSuperVisitable, TypeVisitor};
+use rustc_span::def_id::LocalDefId;
 use rustc_span::source_map::Span;
 use rustc_target::spec::abi::Abi;
 use rustc_trait_selection::traits;
@@ -80,7 +80,7 @@ fn check_closure(
 
         debug!(?bound_sig, ?liberated_sig);
 
-        let mut fcx = FnCtxt::new(self, self.param_env.without_const(), body.value.hir_id);
+        let mut fcx = FnCtxt::new(self, self.param_env.without_const(), closure.def_id);
         let generator_types = check_fn(
             &mut fcx,
             liberated_sig,
@@ -620,8 +620,9 @@ fn supplied_sig_of_closure(
                 // function.
                 Some(hir::GeneratorKind::Async(hir::AsyncGeneratorKind::Fn)) => {
                     debug!("closure is async fn body");
-                    self.deduce_future_output_from_obligations(expr_def_id, body.id().hir_id)
-                        .unwrap_or_else(|| {
+                    let def_id = self.tcx.hir().body_owner_def_id(body.id());
+                    self.deduce_future_output_from_obligations(expr_def_id, def_id).unwrap_or_else(
+                        || {
                             // AFAIK, deducing the future output
                             // always succeeds *except* in error cases
                             // like #65159. I'd like to return Error
@@ -630,7 +631,8 @@ fn supplied_sig_of_closure(
                             // *have* reported an
                             // error. --nikomatsakis
                             astconv.ty_infer(None, decl.output.span())
-                        })
+                        },
+                    )
                 }
 
                 _ => astconv.ty_infer(None, decl.output.span()),
@@ -665,7 +667,7 @@ fn supplied_sig_of_closure(
     fn deduce_future_output_from_obligations(
         &self,
         expr_def_id: LocalDefId,
-        body_id: hir::HirId,
+        body_def_id: LocalDefId,
     ) -> Option<Ty<'tcx>> {
         let ret_coercion = self.ret_coercion.as_ref().unwrap_or_else(|| {
             span_bug!(self.tcx.def_span(expr_def_id), "async fn generator outside of a fn")
@@ -725,7 +727,7 @@ fn deduce_future_output_from_obligations(
         let InferOk { value: output_ty, obligations } = self
             .replace_opaque_types_with_inference_vars(
                 output_ty,
-                body_id,
+                body_def_id,
                 self.tcx.def_span(expr_def_id),
                 self.param_env,
             );
index bbf7b81a2cc66ca82ccff36b50b0947c99710b77..1a0715a91cb0c0e8718401a00987bc54803ae36a 100644 (file)
@@ -1613,12 +1613,14 @@ pub(crate) fn coerce_inner<'a>(
                 if visitor.ret_exprs.len() > 0 && let Some(expr) = expression {
                     self.note_unreachable_loop_return(&mut err, &expr, &visitor.ret_exprs);
                 }
+
                 let reported = err.emit_unless(unsized_return);
 
                 self.final_ty = Some(fcx.tcx.ty_error_with_guaranteed(reported));
             }
         }
     }
+
     fn note_unreachable_loop_return(
         &self,
         err: &mut Diagnostic,
index bd1626dff79515908687a64fd667223ab24ca127..a7b6a5c0331fc9722e126952c4198d309c27e86c 100644 (file)
@@ -59,9 +59,10 @@ pub fn emit_type_mismatch_suggestions(
             || self.suggest_copied_or_cloned(err, expr, expr_ty, expected)
             || self.suggest_clone_for_ref(err, expr, expr_ty, expected)
             || self.suggest_into(err, expr, expr_ty, expected)
-            || self.suggest_floating_point_literal(err, expr, expected);
+            || self.suggest_floating_point_literal(err, expr, expected)
+            || self.note_result_coercion(err, expr, expected, expr_ty);
         if !suggested {
-            self.point_at_expr_source_of_inferred_type(err, expr, expr_ty, expected);
+            self.point_at_expr_source_of_inferred_type(err, expr, expr_ty, expected, expr.span);
         }
     }
 
@@ -81,7 +82,6 @@ pub fn emit_coerce_suggestions(
         self.annotate_expected_due_to_let_ty(err, expr, error);
         self.emit_type_mismatch_suggestions(err, expr, expr_ty, expected, expected_ty_expr, error);
         self.note_type_is_not_clone(err, expected, expr_ty, expr);
-        self.note_need_for_fn_pointer(err, expected, expr_ty);
         self.note_internal_mutation_in_method(err, expr, expected, expr_ty);
         self.check_for_range_as_method_call(err, expr, expr_ty, expected);
         self.check_for_binding_assigned_block_without_tail_expression(err, expr, expr_ty, expected);
@@ -222,6 +222,7 @@ pub fn point_at_expr_source_of_inferred_type(
         expr: &hir::Expr<'_>,
         found: Ty<'tcx>,
         expected: Ty<'tcx>,
+        mismatch_span: Span,
     ) -> bool {
         let map = self.tcx.hir();
 
@@ -270,7 +271,7 @@ fn visit_expr(&mut self, ex: &'v hir::Expr<'v>) {
             lt_op: |_| self.tcx.lifetimes.re_erased,
             ct_op: |c| c,
             ty_op: |t| match *t.kind() {
-                ty::Infer(ty::TyVar(vid)) => self.tcx.mk_ty_infer(ty::TyVar(self.root_var(vid))),
+                ty::Infer(ty::TyVar(_)) => self.tcx.mk_ty_var(ty::TyVid::from_u32(0)),
                 ty::Infer(ty::IntVar(_)) => {
                     self.tcx.mk_ty_infer(ty::IntVar(ty::IntVid { index: 0 }))
                 }
@@ -281,7 +282,7 @@ fn visit_expr(&mut self, ex: &'v hir::Expr<'v>) {
             },
         };
         let mut prev = eraser.fold_ty(ty);
-        let mut prev_span = None;
+        let mut prev_span: Option<Span> = None;
 
         for binding in expr_finder.uses {
             // In every expression where the binding is referenced, we will look at that
@@ -333,13 +334,15 @@ fn visit_expr(&mut self, ex: &'v hir::Expr<'v>) {
                             // inferred in this method call.
                             let arg = &args[i];
                             let arg_ty = self.node_ty(arg.hir_id);
-                            err.span_label(
-                                arg.span,
-                                &format!(
-                                    "this is of type `{arg_ty}`, which causes `{ident}` to be \
-                                     inferred as `{ty}`",
-                                ),
-                            );
+                            if !arg.span.overlaps(mismatch_span) {
+                                err.span_label(
+                                    arg.span,
+                                    &format!(
+                                        "this is of type `{arg_ty}`, which causes `{ident}` to be \
+                                        inferred as `{ty}`",
+                                    ),
+                                );
+                            }
                             param_args.insert(param_ty, (arg, arg_ty));
                         }
                     }
@@ -382,12 +385,13 @@ fn visit_expr(&mut self, ex: &'v hir::Expr<'v>) {
                     && self.can_eq(self.param_env, ty, found).is_ok()
                 {
                     // We only point at the first place where the found type was inferred.
+                    if !segment.ident.span.overlaps(mismatch_span) {
                     err.span_label(
                         segment.ident.span,
                         with_forced_trimmed_paths!(format!(
                             "here the type of `{ident}` is inferred to be `{ty}`",
                         )),
-                    );
+                    );}
                     break;
                 } else if !param_args.is_empty() {
                     break;
@@ -406,12 +410,14 @@ fn visit_expr(&mut self, ex: &'v hir::Expr<'v>) {
                     // We use the *previous* span because if the type is known *here* it means
                     // it was *evaluated earlier*. We don't do this for method calls because we
                     // evaluate the method's self type eagerly, but not in any other case.
-                    err.span_label(
-                        span,
-                        with_forced_trimmed_paths!(format!(
-                            "here the type of `{ident}` is inferred to be `{ty}`",
-                        )),
-                    );
+                    if !span.overlaps(mismatch_span) {
+                        err.span_label(
+                            span,
+                            with_forced_trimmed_paths!(format!(
+                                "here the type of `{ident}` is inferred to be `{ty}`",
+                            )),
+                        );
+                    }
                     break;
                 }
                 prev = ty;
@@ -697,6 +703,56 @@ fn annotate_alternative_method_deref(
         );
     }
 
+    pub(crate) fn note_result_coercion(
+        &self,
+        err: &mut Diagnostic,
+        expr: &hir::Expr<'tcx>,
+        expected: Ty<'tcx>,
+        found: Ty<'tcx>,
+    ) -> bool {
+        let ty::Adt(e, substs_e) = expected.kind() else { return false; };
+        let ty::Adt(f, substs_f) = found.kind() else { return false; };
+        if e.did() != f.did() {
+            return false;
+        }
+        if Some(e.did()) != self.tcx.get_diagnostic_item(sym::Result) {
+            return false;
+        }
+        let map = self.tcx.hir();
+        if let Some(hir::Node::Expr(expr)) = map.find_parent(expr.hir_id)
+            && let hir::ExprKind::Ret(_) = expr.kind
+        {
+            // `return foo;`
+        } else if map.get_return_block(expr.hir_id).is_some() {
+            // Function's tail expression.
+        } else {
+            return false;
+        }
+        let e = substs_e.type_at(1);
+        let f = substs_f.type_at(1);
+        if self
+            .infcx
+            .type_implements_trait(
+                self.tcx.get_diagnostic_item(sym::Into).unwrap(),
+                [f, e],
+                self.param_env,
+            )
+            .must_apply_modulo_regions()
+        {
+            err.multipart_suggestion(
+                "use `?` to coerce and return an appropriate `Err`, and wrap the resulting value \
+                 in `Ok` so the expression remains of type `Result`",
+                vec![
+                    (expr.span.shrink_to_lo(), "Ok(".to_string()),
+                    (expr.span.shrink_to_hi(), "?)".to_string()),
+                ],
+                Applicability::MaybeIncorrect,
+            );
+            return true;
+        }
+        false
+    }
+
     /// If the expected type is an enum (Issue #55250) with any variants whose
     /// sole field is of the found type, suggest such variants. (Issue #42764)
     fn suggest_compatible_variants(
index bc7474cdfcf3de1023b1b2af40ab46d7a82cb52b..058984731040a2356ff126d4307b787ddf2a1c46 100644 (file)
@@ -852,7 +852,7 @@ pub(super) fn check_return_expr(
             // Point any obligations that were registered due to opaque type
             // inference at the return expression.
             self.select_obligations_where_possible(|errors| {
-                self.point_at_return_for_opaque_ty_error(errors, span, return_expr_ty);
+                self.point_at_return_for_opaque_ty_error(errors, span, return_expr_ty, return_expr.span);
             });
         }
     }
@@ -862,9 +862,10 @@ fn point_at_return_for_opaque_ty_error(
         errors: &mut Vec<traits::FulfillmentError<'tcx>>,
         span: Span,
         return_expr_ty: Ty<'tcx>,
+        return_span: Span,
     ) {
         // Don't point at the whole block if it's empty
-        if span == self.tcx.hir().span(self.body_id) {
+        if span == return_span {
             return;
         }
         for err in errors {
@@ -1374,7 +1375,8 @@ fn check_expr_const_block(
         let body = self.tcx.hir().body(anon_const.body);
 
         // Create a new function context.
-        let fcx = FnCtxt::new(self, self.param_env.with_const(), body.value.hir_id);
+        let def_id = anon_const.def_id;
+        let fcx = FnCtxt::new(self, self.param_env.with_const(), def_id);
         crate::GatherLocalsVisitor::new(&fcx).visit_body(body);
 
         let ty = fcx.check_expr_with_expectation(&body.value, expected);
@@ -2151,13 +2153,18 @@ fn available_field_names(
         variant: &'tcx ty::VariantDef,
         access_span: Span,
     ) -> Vec<Symbol> {
+        let body_owner_hir_id = self.tcx.hir().local_def_id_to_hir_id(self.body_id);
         variant
             .fields
             .iter()
             .filter(|field| {
                 let def_scope = self
                     .tcx
-                    .adjust_ident_and_get_scope(field.ident(self.tcx), variant.def_id, self.body_id)
+                    .adjust_ident_and_get_scope(
+                        field.ident(self.tcx),
+                        variant.def_id,
+                        body_owner_hir_id,
+                    )
                     .1;
                 field.vis.is_accessible_from(def_scope, self.tcx)
                     && !matches!(
@@ -2199,8 +2206,9 @@ fn check_field(
             match deref_base_ty.kind() {
                 ty::Adt(base_def, substs) if !base_def.is_enum() => {
                     debug!("struct named {:?}", deref_base_ty);
+                    let body_hir_id = self.tcx.hir().local_def_id_to_hir_id(self.body_id);
                     let (ident, def_scope) =
-                        self.tcx.adjust_ident_and_get_scope(field, base_def.did(), self.body_id);
+                        self.tcx.adjust_ident_and_get_scope(field, base_def.did(), body_hir_id);
                     let fields = &base_def.non_enum_variant().fields;
                     if let Some(index) = fields
                         .iter()
@@ -2538,7 +2546,7 @@ fn ban_take_value_of_method(&self, expr: &hir::Expr<'tcx>, expr_t: Ty<'tcx>, fie
     }
 
     fn point_at_param_definition(&self, err: &mut Diagnostic, param: ty::ParamTy) {
-        let generics = self.tcx.generics_of(self.body_id.owner.to_def_id());
+        let generics = self.tcx.generics_of(self.body_id);
         let generic_param = generics.type_param(&param, self.tcx);
         if let ty::GenericParamDefKind::Type { synthetic: true, .. } = generic_param.kind {
             return;
index 6ed8adb47425a80197d6a2453f54302953fbb376..e9858aef6d0bf4513ae81fed05775cbac54e353d 100644 (file)
@@ -926,43 +926,6 @@ pub(in super::super) fn note_internal_mutation_in_method(
         }
     }
 
-    pub(in super::super) fn note_need_for_fn_pointer(
-        &self,
-        err: &mut Diagnostic,
-        expected: Ty<'tcx>,
-        found: Ty<'tcx>,
-    ) {
-        let (sig, did, substs) = match (&expected.kind(), &found.kind()) {
-            (ty::FnDef(did1, substs1), ty::FnDef(did2, substs2)) => {
-                let sig1 = self.tcx.bound_fn_sig(*did1).subst(self.tcx, substs1);
-                let sig2 = self.tcx.bound_fn_sig(*did2).subst(self.tcx, substs2);
-                if sig1 != sig2 {
-                    return;
-                }
-                err.note(
-                    "different `fn` items always have unique types, even if their signatures are \
-                     the same",
-                );
-                (sig1, *did1, substs1)
-            }
-            (ty::FnDef(did, substs), ty::FnPtr(sig2)) => {
-                let sig1 = self.tcx.bound_fn_sig(*did).subst(self.tcx, substs);
-                if sig1 != *sig2 {
-                    return;
-                }
-                (sig1, *did, substs)
-            }
-            _ => return,
-        };
-        err.help(&format!("change the expected type to be function pointer `{}`", sig));
-        err.help(&format!(
-            "if the expected type is due to type inference, cast the expected `fn` to a function \
-             pointer: `{} as {}`",
-            self.tcx.def_path_str_with_substs(did, substs),
-            sig
-        ));
-    }
-
     // Instantiates the given path, which must refer to an item with the given
     // number of type parameters and type.
     #[instrument(skip(self, span), level = "debug")]
index c9609e69439812477b27d84f3d037abe82167ea0..e78c76d5dde7031337b15a34272520d5438cebff 100644 (file)
@@ -808,7 +808,13 @@ fn has_error_or_infer<'tcx>(tys: impl IntoIterator<Item = Ty<'tcx>>) -> bool {
                     kind: TypeVariableOriginKind::MiscVariable,
                     span: full_call_span,
                 });
-                self.point_at_expr_source_of_inferred_type(&mut err, rcvr, expected, callee_ty);
+                self.point_at_expr_source_of_inferred_type(
+                    &mut err,
+                    rcvr,
+                    expected,
+                    callee_ty,
+                    provided_arg_span,
+                );
             }
             // Call out where the function is defined
             self.label_fn_like(
@@ -2126,7 +2132,7 @@ fn label_fn_like(
             match *callee_ty.kind() {
                 ty::Param(param) => {
                     let param =
-                        self.tcx.generics_of(self.body_id.owner).type_param(&param, self.tcx);
+                        self.tcx.generics_of(self.body_id).type_param(&param, self.tcx);
                     if param.kind.is_synthetic() {
                         // if it's `impl Fn() -> ..` then just fall down to the def-id based logic
                         def_id = param.def_id;
@@ -2135,7 +2141,7 @@ fn label_fn_like(
                         // and point at that.
                         let instantiated = self
                             .tcx
-                            .explicit_predicates_of(self.body_id.owner)
+                            .explicit_predicates_of(self.body_id)
                             .instantiate_identity(self.tcx);
                         // FIXME(compiler-errors): This could be problematic if something has two
                         // fn-like predicates with different args, but callable types really never
index 428fde642bc0901bff4a7fb92c8c6cb6c589c100..8724e69cc5134fae02a13b770b24e1b85851cba0 100644 (file)
@@ -10,7 +10,7 @@
 use crate::coercion::DynamicCoerceMany;
 use crate::{Diverges, EnclosingBreakables, Inherited};
 use rustc_hir as hir;
-use rustc_hir::def_id::DefId;
+use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_hir_analysis::astconv::AstConv;
 use rustc_infer::infer;
 use rustc_infer::infer::error_reporting::TypeErrCtxt;
@@ -38,7 +38,7 @@
 /// [`ItemCtxt`]: rustc_hir_analysis::collect::ItemCtxt
 /// [`InferCtxt`]: infer::InferCtxt
 pub struct FnCtxt<'a, 'tcx> {
-    pub(super) body_id: hir::HirId,
+    pub(super) body_id: LocalDefId,
 
     /// The parameter environment used for proving trait obligations
     /// in this function. This can change when we descend into
@@ -117,7 +117,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     pub fn new(
         inh: &'a Inherited<'tcx>,
         param_env: ty::ParamEnv<'tcx>,
-        body_id: hir::HirId,
+        body_id: LocalDefId,
     ) -> FnCtxt<'a, 'tcx> {
         FnCtxt {
             body_id,
@@ -204,7 +204,7 @@ fn tcx<'b>(&'b self) -> TyCtxt<'tcx> {
     }
 
     fn item_def_id(&self) -> DefId {
-        self.body_id.owner.to_def_id()
+        self.body_id.to_def_id()
     }
 
     fn get_type_parameter_bounds(
index 4d673ac91472f10f2351b4ba265eaed4cd6b8329..6046e55c65c18366c2b2cb10fae1cd1a390fe7f1 100644 (file)
@@ -31,7 +31,7 @@ pub(crate) fn body_fn_sig(&self) -> Option<ty::FnSig<'tcx>> {
         self.typeck_results
             .borrow()
             .liberated_fn_sigs()
-            .get(self.tcx.hir().parent_id(self.body_id))
+            .get(self.tcx.hir().local_def_id_to_hir_id(self.body_id))
             .copied()
     }
 
@@ -164,7 +164,8 @@ pub(in super::super) fn extract_callable_info(
         &self,
         ty: Ty<'tcx>,
     ) -> Option<(DefIdOrName, Ty<'tcx>, Vec<Ty<'tcx>>)> {
-        self.err_ctxt().extract_callable_info(self.body_id, self.param_env, ty)
+        let body_hir_id = self.tcx.hir().local_def_id_to_hir_id(self.body_id);
+        self.err_ctxt().extract_callable_info(body_hir_id, self.param_env, ty)
     }
 
     pub fn suggest_two_fn_call(
index 3c873024c924f3837c473312fb3c0395be8eeaa1..2c76582f2ec8fbd14b9b911b4f922498a747b4d0 100644 (file)
@@ -38,6 +38,7 @@ fn unpack_option_like<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> {
 impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     pub fn check_transmute(&self, from: Ty<'tcx>, to: Ty<'tcx>, hir_id: HirId) {
         let tcx = self.tcx;
+        let dl = &tcx.data_layout;
         let span = tcx.hir().span(hir_id);
         let normalize = |ty| {
             let ty = self.resolve_vars_if_possible(ty);
@@ -69,7 +70,7 @@ pub fn check_transmute(&self, from: Ty<'tcx>, to: Ty<'tcx>, hir_id: HirId) {
             // Special-case transmuting from `typeof(function)` and
             // `Option<typeof(function)>` to present a clearer error.
             let from = unpack_option_like(tcx, from);
-            if let (&ty::FnDef(..), SizeSkeleton::Known(size_to)) = (from.kind(), sk_to) && size_to == Pointer.size(&tcx) {
+            if let (&ty::FnDef(..), SizeSkeleton::Known(size_to)) = (from.kind(), sk_to) && size_to == Pointer(dl.instruction_address_space).size(&tcx) {
                 struct_span_err!(tcx.sess, span, E0591, "can't transmute zero-sized type")
                     .note(&format!("source type: {from}"))
                     .note(&format!("target type: {to}"))
index 7ddf9eaa4d8995463fa730d5ad653c536b174d2b..bb487facc23fdf9d58eb2a640181ac005749fb08 100644 (file)
@@ -201,7 +201,7 @@ fn typeck_with_fallback<'tcx>(
 
     let typeck_results = Inherited::build(tcx, def_id).enter(|inh| {
         let param_env = tcx.param_env(def_id);
-        let mut fcx = FnCtxt::new(&inh, param_env, body.value.hir_id);
+        let mut fcx = FnCtxt::new(&inh, param_env, def_id);
 
         if let Some(hir::FnSig { header, decl, .. }) = fn_sig {
             let fn_sig = if rustc_hir_analysis::collect::get_infer_ret_ty(&decl.output).is_some() {
index 9c06a22315bcba12189377e2770e9884588d5e5f..939f9c93a02cab29174b1c48713fd1498a731138 100644 (file)
@@ -508,9 +508,10 @@ fn method_autoderef_steps<'tcx>(
     let (ref infcx, goal, inference_vars) = tcx.infer_ctxt().build_with_canonical(DUMMY_SP, &goal);
     let ParamEnvAnd { param_env, value: self_ty } = goal;
 
-    let mut autoderef = Autoderef::new(infcx, param_env, hir::CRATE_HIR_ID, DUMMY_SP, self_ty)
-        .include_raw_pointers()
-        .silence_errors();
+    let mut autoderef =
+        Autoderef::new(infcx, param_env, hir::def_id::CRATE_DEF_ID, DUMMY_SP, self_ty)
+            .include_raw_pointers()
+            .silence_errors();
     let mut reached_raw_pointer = false;
     let mut steps: Vec<_> = autoderef
         .by_ref()
@@ -610,10 +611,9 @@ fn reset(&mut self) {
     fn push_candidate(&mut self, candidate: Candidate<'tcx>, is_inherent: bool) {
         let is_accessible = if let Some(name) = self.method_name {
             let item = candidate.item;
-            let def_scope = self
-                .tcx
-                .adjust_ident_and_get_scope(name, item.container_id(self.tcx), self.body_id)
-                .1;
+            let hir_id = self.tcx.hir().local_def_id_to_hir_id(self.body_id);
+            let def_scope =
+                self.tcx.adjust_ident_and_get_scope(name, item.container_id(self.tcx), hir_id).1;
             item.visibility(self.tcx).is_accessible_from(def_scope, self.tcx)
         } else {
             true
index 8c54e9bdb5fb3a3ae7670f01c5d8e3b66c346b98..7a2791b11bfdd0d58951bd071f09bb0c50a59e1b 100644 (file)
@@ -352,7 +352,7 @@ pub fn report_no_match_method_error(
 
         let ty_span = match rcvr_ty.kind() {
             ty::Param(param_type) => {
-                Some(param_type.span_from_generics(self.tcx, self.body_id.owner.to_def_id()))
+                Some(param_type.span_from_generics(self.tcx, self.body_id.to_def_id()))
             }
             ty::Adt(def, _) if def.did().is_local() => Some(tcx.def_span(def.did())),
             _ => None,
@@ -403,7 +403,6 @@ pub fn report_no_match_method_error(
                 args,
                 sugg_span,
             );
-
             self.note_candidates_on_method_error(
                 rcvr_ty,
                 item_name,
@@ -496,9 +495,7 @@ pub fn report_no_match_method_error(
                             ty::Param(_) => {
                                 // Account for `fn` items like in `issue-35677.rs` to
                                 // suggest restricting its type params.
-                                let parent_body =
-                                    hir.body_owner(hir::BodyId { hir_id: self.body_id });
-                                Some(hir.get(parent_body))
+                                Some(hir.get_by_def_id(self.body_id))
                             }
                             ty::Adt(def, _) => {
                                 def.did().as_local().map(|def_id| hir.get_by_def_id(def_id))
@@ -1343,7 +1340,7 @@ fn suggest_calling_field_as_fn(
             _ => None,
         });
         if let Some((field, field_ty)) = field_receiver {
-            let scope = tcx.parent_module(self.body_id);
+            let scope = tcx.parent_module_from_def_id(self.body_id);
             let is_accessible = field.vis.is_accessible_from(scope, tcx);
 
             if is_accessible {
@@ -1593,7 +1590,8 @@ pub(crate) fn suggest_assoc_method_call(&self, segs: &[PathSegment<'_>]) {
                 else { return };
 
         let map = self.infcx.tcx.hir();
-        let body = map.body(rustc_hir::BodyId { hir_id: self.body_id });
+        let body_id = self.tcx.hir().body_owned_by(self.body_id);
+        let body = map.body(body_id);
         struct LetVisitor<'a> {
             result: Option<&'a hir::Expr<'a>>,
             ident_name: Symbol,
@@ -2195,7 +2193,7 @@ fn suggest_use_candidates(&self, err: &mut Diagnostic, msg: String, candidates:
             true
         });
 
-        let module_did = self.tcx.parent_module(self.body_id);
+        let module_did = self.tcx.parent_module_from_def_id(self.body_id);
         let (module, _, _) = self.tcx.hir().get_module(module_did);
         let span = module.spans.inject_use_span;
 
@@ -2517,7 +2515,7 @@ fn suggest_traits_to_import(
             };
             // Obtain the span for `param` and use it for a structured suggestion.
             if let Some(param) = param_type {
-                let generics = self.tcx.generics_of(self.body_id.owner.to_def_id());
+                let generics = self.tcx.generics_of(self.body_id.to_def_id());
                 let type_param = generics.type_param(param, self.tcx);
                 let hir = self.tcx.hir();
                 if let Some(def_id) = type_param.def_id.as_local() {
index 28fd03b878b2b69b2da3ef46b59a09823f1ea5f3..d19a0007f0880f7ac0f7083ea5cef9bbb23444dc 100644 (file)
@@ -79,6 +79,7 @@
 use std::{cmp, fmt, iter};
 
 mod note;
+mod note_and_explain;
 mod suggest;
 
 pub(crate) mod need_type_info;
@@ -1841,19 +1842,13 @@ enum Similar<'tcx> {
                 self.suggest_as_ref_where_appropriate(span, &exp_found, diag);
                 self.suggest_accessing_field_where_appropriate(cause, &exp_found, diag);
                 self.suggest_await_on_expect_found(cause, span, &exp_found, diag);
+                self.suggest_function_pointers(cause, span, &exp_found, diag);
             }
         }
 
-        // In some (most?) cases cause.body_id points to actual body, but in some cases
-        // it's an actual definition. According to the comments (e.g. in
-        // rustc_hir_analysis/check/compare_impl_item.rs:compare_predicate_entailment) the latter
-        // is relied upon by some other code. This might (or might not) need cleanup.
-        let body_owner_def_id =
-            self.tcx.hir().opt_local_def_id(cause.body_id).unwrap_or_else(|| {
-                self.tcx.hir().body_owner_def_id(hir::BodyId { hir_id: cause.body_id })
-            });
         self.check_and_note_conflicting_crates(diag, terr);
-        self.tcx.note_and_explain_type_err(diag, terr, cause, span, body_owner_def_id.to_def_id());
+
+        self.note_and_explain_type_err(diag, terr, cause, span, cause.body_id.to_def_id());
 
         if let Some(ValuePairs::PolyTraitRefs(exp_found)) = values
             && let ty::Closure(def_id, _) = exp_found.expected.skip_binder().self_ty().kind()
@@ -2585,7 +2580,7 @@ pub fn is_try_conversion(&self, span: Span, trait_def_id: DefId) -> bool {
     /// with the other type. A TyVar inference type is compatible with any type, and an IntVar or
     /// FloatVar inference type are compatible with themselves or their concrete types (Int and
     /// Float types, respectively). When comparing two ADTs, these rules apply recursively.
-    pub fn same_type_modulo_infer(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> bool {
+    pub fn same_type_modulo_infer<T: relate::Relate<'tcx>>(&self, a: T, b: T) -> bool {
         let (a, b) = self.resolve_vars_if_possible((a, b));
         SameTypeModuloInfer(self).relate(a, b).is_ok()
     }
diff --git a/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs b/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs
new file mode 100644 (file)
index 0000000..425cde3
--- /dev/null
@@ -0,0 +1,654 @@
+use super::TypeErrCtxt;
+use rustc_errors::Applicability::{MachineApplicable, MaybeIncorrect};
+use rustc_errors::{pluralize, Diagnostic, MultiSpan};
+use rustc_hir::{self as hir, def::DefKind};
+use rustc_middle::traits::ObligationCauseCode;
+use rustc_middle::ty::error::ExpectedFound;
+use rustc_middle::ty::print::Printer;
+use rustc_middle::{
+    traits::ObligationCause,
+    ty::{self, error::TypeError, print::FmtPrinter, suggest_constraining_type_param, Ty},
+};
+use rustc_span::{def_id::DefId, sym, BytePos, Span, Symbol};
+
+impl<'tcx> TypeErrCtxt<'_, 'tcx> {
+    pub fn note_and_explain_type_err(
+        &self,
+        diag: &mut Diagnostic,
+        err: TypeError<'tcx>,
+        cause: &ObligationCause<'tcx>,
+        sp: Span,
+        body_owner_def_id: DefId,
+    ) {
+        use ty::error::TypeError::*;
+        debug!("note_and_explain_type_err err={:?} cause={:?}", err, cause);
+
+        let tcx = self.tcx;
+
+        match err {
+            ArgumentSorts(values, _) | Sorts(values) => {
+                match (values.expected.kind(), values.found.kind()) {
+                    (ty::Closure(..), ty::Closure(..)) => {
+                        diag.note("no two closures, even if identical, have the same type");
+                        diag.help("consider boxing your closure and/or using it as a trait object");
+                    }
+                    (ty::Alias(ty::Opaque, ..), ty::Alias(ty::Opaque, ..)) => {
+                        // Issue #63167
+                        diag.note("distinct uses of `impl Trait` result in different opaque types");
+                    }
+                    (ty::Float(_), ty::Infer(ty::IntVar(_)))
+                        if let Ok(
+                            // Issue #53280
+                            snippet,
+                        ) = tcx.sess.source_map().span_to_snippet(sp) =>
+                    {
+                        if snippet.chars().all(|c| c.is_digit(10) || c == '-' || c == '_') {
+                            diag.span_suggestion(
+                                sp,
+                                "use a float literal",
+                                format!("{}.0", snippet),
+                                MachineApplicable,
+                            );
+                        }
+                    }
+                    (ty::Param(expected), ty::Param(found)) => {
+                        let generics = tcx.generics_of(body_owner_def_id);
+                        let e_span = tcx.def_span(generics.type_param(expected, tcx).def_id);
+                        if !sp.contains(e_span) {
+                            diag.span_label(e_span, "expected type parameter");
+                        }
+                        let f_span = tcx.def_span(generics.type_param(found, tcx).def_id);
+                        if !sp.contains(f_span) {
+                            diag.span_label(f_span, "found type parameter");
+                        }
+                        diag.note(
+                            "a type parameter was expected, but a different one was found; \
+                             you might be missing a type parameter or trait bound",
+                        );
+                        diag.note(
+                            "for more information, visit \
+                             https://doc.rust-lang.org/book/ch10-02-traits.html\
+                             #traits-as-parameters",
+                        );
+                    }
+                    (ty::Alias(ty::Projection, _), ty::Alias(ty::Projection, _)) => {
+                        diag.note("an associated type was expected, but a different one was found");
+                    }
+                    (ty::Param(p), ty::Alias(ty::Projection, proj)) | (ty::Alias(ty::Projection, proj), ty::Param(p))
+                        if tcx.def_kind(proj.def_id) != DefKind::ImplTraitPlaceholder =>
+                    {
+                        let generics = tcx.generics_of(body_owner_def_id);
+                        let p_span = tcx.def_span(generics.type_param(p, tcx).def_id);
+                        if !sp.contains(p_span) {
+                            diag.span_label(p_span, "this type parameter");
+                        }
+                        let hir = tcx.hir();
+                        let mut note = true;
+                        if let Some(generics) = generics
+                            .type_param(p, tcx)
+                            .def_id
+                            .as_local()
+                            .map(|id| hir.local_def_id_to_hir_id(id))
+                            .and_then(|id| tcx.hir().find_parent(id))
+                            .as_ref()
+                            .and_then(|node| node.generics())
+                        {
+                            // Synthesize the associated type restriction `Add<Output = Expected>`.
+                            // FIXME: extract this logic for use in other diagnostics.
+                            let (trait_ref, assoc_substs) = proj.trait_ref_and_own_substs(tcx);
+                            let path =
+                                tcx.def_path_str_with_substs(trait_ref.def_id, trait_ref.substs);
+                            let item_name = tcx.item_name(proj.def_id);
+                            let item_args = self.format_generic_args(assoc_substs);
+
+                            let path = if path.ends_with('>') {
+                                format!(
+                                    "{}, {}{} = {}>",
+                                    &path[..path.len() - 1],
+                                    item_name,
+                                    item_args,
+                                    p
+                                )
+                            } else {
+                                format!("{}<{}{} = {}>", path, item_name, item_args, p)
+                            };
+                            note = !suggest_constraining_type_param(
+                                tcx,
+                                generics,
+                                diag,
+                                &format!("{}", proj.self_ty()),
+                                &path,
+                                None,
+                            );
+                        }
+                        if note {
+                            diag.note("you might be missing a type parameter or trait bound");
+                        }
+                    }
+                    (ty::Param(p), ty::Dynamic(..) | ty::Alias(ty::Opaque, ..))
+                    | (ty::Dynamic(..) | ty::Alias(ty::Opaque, ..), ty::Param(p)) => {
+                        let generics = tcx.generics_of(body_owner_def_id);
+                        let p_span = tcx.def_span(generics.type_param(p, tcx).def_id);
+                        if !sp.contains(p_span) {
+                            diag.span_label(p_span, "this type parameter");
+                        }
+                        diag.help("type parameters must be constrained to match other types");
+                        if tcx.sess.teach(&diag.get_code().unwrap()) {
+                            diag.help(
+                                "given a type parameter `T` and a method `foo`:
+```
+trait Trait<T> { fn foo(&tcx) -> T; }
+```
+the only ways to implement method `foo` are:
+- constrain `T` with an explicit type:
+```
+impl Trait<String> for X {
+    fn foo(&tcx) -> String { String::new() }
+}
+```
+- add a trait bound to `T` and call a method on that trait that returns `Self`:
+```
+impl<T: std::default::Default> Trait<T> for X {
+    fn foo(&tcx) -> T { <T as std::default::Default>::default() }
+}
+```
+- change `foo` to return an argument of type `T`:
+```
+impl<T> Trait<T> for X {
+    fn foo(&tcx, x: T) -> T { x }
+}
+```",
+                            );
+                        }
+                        diag.note(
+                            "for more information, visit \
+                             https://doc.rust-lang.org/book/ch10-02-traits.html\
+                             #traits-as-parameters",
+                        );
+                    }
+                    (ty::Param(p), ty::Closure(..) | ty::Generator(..)) => {
+                        let generics = tcx.generics_of(body_owner_def_id);
+                        let p_span = tcx.def_span(generics.type_param(p, tcx).def_id);
+                        if !sp.contains(p_span) {
+                            diag.span_label(p_span, "this type parameter");
+                        }
+                        diag.help(&format!(
+                            "every closure has a distinct type and so could not always match the \
+                             caller-chosen type of parameter `{}`",
+                            p
+                        ));
+                    }
+                    (ty::Param(p), _) | (_, ty::Param(p)) => {
+                        let generics = tcx.generics_of(body_owner_def_id);
+                        let p_span = tcx.def_span(generics.type_param(p, tcx).def_id);
+                        if !sp.contains(p_span) {
+                            diag.span_label(p_span, "this type parameter");
+                        }
+                    }
+                    (ty::Alias(ty::Projection, proj_ty), _) if tcx.def_kind(proj_ty.def_id) != DefKind::ImplTraitPlaceholder => {
+                        self.expected_projection(
+                            diag,
+                            proj_ty,
+                            values,
+                            body_owner_def_id,
+                            cause.code(),
+                        );
+                    }
+                    (_, ty::Alias(ty::Projection, proj_ty)) if tcx.def_kind(proj_ty.def_id) != DefKind::ImplTraitPlaceholder => {
+                        let msg = format!(
+                            "consider constraining the associated type `{}` to `{}`",
+                            values.found, values.expected,
+                        );
+                        if !(self.suggest_constraining_opaque_associated_type(
+                            diag,
+                            &msg,
+                            proj_ty,
+                            values.expected,
+                        ) || self.suggest_constraint(
+                            diag,
+                            &msg,
+                            body_owner_def_id,
+                            proj_ty,
+                            values.expected,
+                        )) {
+                            diag.help(&msg);
+                            diag.note(
+                                "for more information, visit \
+                                https://doc.rust-lang.org/book/ch19-03-advanced-traits.html",
+                            );
+                        }
+                    }
+                    _ => {}
+                }
+                debug!(
+                    "note_and_explain_type_err expected={:?} ({:?}) found={:?} ({:?})",
+                    values.expected,
+                    values.expected.kind(),
+                    values.found,
+                    values.found.kind(),
+                );
+            }
+            CyclicTy(ty) => {
+                // Watch out for various cases of cyclic types and try to explain.
+                if ty.is_closure() || ty.is_generator() {
+                    diag.note(
+                        "closures cannot capture themselves or take themselves as argument;\n\
+                         this error may be the result of a recent compiler bug-fix,\n\
+                         see issue #46062 <https://github.com/rust-lang/rust/issues/46062>\n\
+                         for more information",
+                    );
+                }
+            }
+            TargetFeatureCast(def_id) => {
+                let target_spans = tcx.get_attrs(def_id, sym::target_feature).map(|attr| attr.span);
+                diag.note(
+                    "functions with `#[target_feature]` can only be coerced to `unsafe` function pointers"
+                );
+                diag.span_labels(target_spans, "`#[target_feature]` added here");
+            }
+            _ => {}
+        }
+    }
+
+    fn suggest_constraint(
+        &self,
+        diag: &mut Diagnostic,
+        msg: &str,
+        body_owner_def_id: DefId,
+        proj_ty: &ty::AliasTy<'tcx>,
+        ty: Ty<'tcx>,
+    ) -> bool {
+        let tcx = self.tcx;
+        let assoc = tcx.associated_item(proj_ty.def_id);
+        let (trait_ref, assoc_substs) = proj_ty.trait_ref_and_own_substs(tcx);
+        if let Some(item) = tcx.hir().get_if_local(body_owner_def_id) {
+            if let Some(hir_generics) = item.generics() {
+                // Get the `DefId` for the type parameter corresponding to `A` in `<A as T>::Foo`.
+                // This will also work for `impl Trait`.
+                let def_id = if let ty::Param(param_ty) = proj_ty.self_ty().kind() {
+                    let generics = tcx.generics_of(body_owner_def_id);
+                    generics.type_param(param_ty, tcx).def_id
+                } else {
+                    return false;
+                };
+                let Some(def_id) = def_id.as_local() else {
+                    return false;
+                };
+
+                // First look in the `where` clause, as this might be
+                // `fn foo<T>(x: T) where T: Trait`.
+                for pred in hir_generics.bounds_for_param(def_id) {
+                    if self.constrain_generic_bound_associated_type_structured_suggestion(
+                        diag,
+                        &trait_ref,
+                        pred.bounds,
+                        &assoc,
+                        assoc_substs,
+                        ty,
+                        msg,
+                        false,
+                    ) {
+                        return true;
+                    }
+                }
+            }
+        }
+        false
+    }
+
+    /// An associated type was expected and a different type was found.
+    ///
+    /// We perform a few different checks to see what we can suggest:
+    ///
+    ///  - In the current item, look for associated functions that return the expected type and
+    ///    suggest calling them. (Not a structured suggestion.)
+    ///  - If any of the item's generic bounds can be constrained, we suggest constraining the
+    ///    associated type to the found type.
+    ///  - If the associated type has a default type and was expected inside of a `trait`, we
+    ///    mention that this is disallowed.
+    ///  - If all other things fail, and the error is not because of a mismatch between the `trait`
+    ///    and the `impl`, we provide a generic `help` to constrain the assoc type or call an assoc
+    ///    fn that returns the type.
+    fn expected_projection(
+        &self,
+        diag: &mut Diagnostic,
+        proj_ty: &ty::AliasTy<'tcx>,
+        values: ExpectedFound<Ty<'tcx>>,
+        body_owner_def_id: DefId,
+        cause_code: &ObligationCauseCode<'_>,
+    ) {
+        let tcx = self.tcx;
+
+        let msg = format!(
+            "consider constraining the associated type `{}` to `{}`",
+            values.expected, values.found
+        );
+        let body_owner = tcx.hir().get_if_local(body_owner_def_id);
+        let current_method_ident = body_owner.and_then(|n| n.ident()).map(|i| i.name);
+
+        // We don't want to suggest calling an assoc fn in a scope where that isn't feasible.
+        let callable_scope = matches!(
+            body_owner,
+            Some(
+                hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(..), .. })
+                    | hir::Node::TraitItem(hir::TraitItem { kind: hir::TraitItemKind::Fn(..), .. })
+                    | hir::Node::ImplItem(hir::ImplItem { kind: hir::ImplItemKind::Fn(..), .. }),
+            )
+        );
+        let impl_comparison =
+            matches!(cause_code, ObligationCauseCode::CompareImplItemObligation { .. });
+        let assoc = tcx.associated_item(proj_ty.def_id);
+        if !callable_scope || impl_comparison {
+            // We do not want to suggest calling functions when the reason of the
+            // type error is a comparison of an `impl` with its `trait` or when the
+            // scope is outside of a `Body`.
+        } else {
+            // If we find a suitable associated function that returns the expected type, we don't
+            // want the more general suggestion later in this method about "consider constraining
+            // the associated type or calling a method that returns the associated type".
+            let point_at_assoc_fn = self.point_at_methods_that_satisfy_associated_type(
+                diag,
+                assoc.container_id(tcx),
+                current_method_ident,
+                proj_ty.def_id,
+                values.expected,
+            );
+            // Possibly suggest constraining the associated type to conform to the
+            // found type.
+            if self.suggest_constraint(diag, &msg, body_owner_def_id, proj_ty, values.found)
+                || point_at_assoc_fn
+            {
+                return;
+            }
+        }
+
+        self.suggest_constraining_opaque_associated_type(diag, &msg, proj_ty, values.found);
+
+        if self.point_at_associated_type(diag, body_owner_def_id, values.found) {
+            return;
+        }
+
+        if !impl_comparison {
+            // Generic suggestion when we can't be more specific.
+            if callable_scope {
+                diag.help(&format!(
+                    "{} or calling a method that returns `{}`",
+                    msg, values.expected
+                ));
+            } else {
+                diag.help(&msg);
+            }
+            diag.note(
+                "for more information, visit \
+                 https://doc.rust-lang.org/book/ch19-03-advanced-traits.html",
+            );
+        }
+        if tcx.sess.teach(&diag.get_code().unwrap()) {
+            diag.help(
+                "given an associated type `T` and a method `foo`:
+```
+trait Trait {
+type T;
+fn foo(&tcx) -> Self::T;
+}
+```
+the only way of implementing method `foo` is to constrain `T` with an explicit associated type:
+```
+impl Trait for X {
+type T = String;
+fn foo(&tcx) -> Self::T { String::new() }
+}
+```",
+            );
+        }
+    }
+
+    /// When the expected `impl Trait` is not defined in the current item, it will come from
+    /// a return type. This can occur when dealing with `TryStream` (#71035).
+    fn suggest_constraining_opaque_associated_type(
+        &self,
+        diag: &mut Diagnostic,
+        msg: &str,
+        proj_ty: &ty::AliasTy<'tcx>,
+        ty: Ty<'tcx>,
+    ) -> bool {
+        let tcx = self.tcx;
+
+        let assoc = tcx.associated_item(proj_ty.def_id);
+        if let ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }) = *proj_ty.self_ty().kind() {
+            let opaque_local_def_id = def_id.as_local();
+            let opaque_hir_ty = if let Some(opaque_local_def_id) = opaque_local_def_id {
+                match &tcx.hir().expect_item(opaque_local_def_id).kind {
+                    hir::ItemKind::OpaqueTy(opaque_hir_ty) => opaque_hir_ty,
+                    _ => bug!("The HirId comes from a `ty::Opaque`"),
+                }
+            } else {
+                return false;
+            };
+
+            let (trait_ref, assoc_substs) = proj_ty.trait_ref_and_own_substs(tcx);
+
+            self.constrain_generic_bound_associated_type_structured_suggestion(
+                diag,
+                &trait_ref,
+                opaque_hir_ty.bounds,
+                assoc,
+                assoc_substs,
+                ty,
+                msg,
+                true,
+            )
+        } else {
+            false
+        }
+    }
+
+    fn point_at_methods_that_satisfy_associated_type(
+        &self,
+        diag: &mut Diagnostic,
+        assoc_container_id: DefId,
+        current_method_ident: Option<Symbol>,
+        proj_ty_item_def_id: DefId,
+        expected: Ty<'tcx>,
+    ) -> bool {
+        let tcx = self.tcx;
+
+        let items = tcx.associated_items(assoc_container_id);
+        // Find all the methods in the trait that could be called to construct the
+        // expected associated type.
+        // FIXME: consider suggesting the use of associated `const`s.
+        let methods: Vec<(Span, String)> = items
+            .in_definition_order()
+            .filter(|item| {
+                ty::AssocKind::Fn == item.kind && Some(item.name) != current_method_ident
+            })
+            .filter_map(|item| {
+                let method = tcx.fn_sig(item.def_id);
+                match *method.output().skip_binder().kind() {
+                    ty::Alias(ty::Projection, ty::AliasTy { def_id: item_def_id, .. })
+                        if item_def_id == proj_ty_item_def_id =>
+                    {
+                        Some((
+                            tcx.def_span(item.def_id),
+                            format!("consider calling `{}`", tcx.def_path_str(item.def_id)),
+                        ))
+                    }
+                    _ => None,
+                }
+            })
+            .collect();
+        if !methods.is_empty() {
+            // Use a single `help:` to show all the methods in the trait that can
+            // be used to construct the expected associated type.
+            let mut span: MultiSpan =
+                methods.iter().map(|(sp, _)| *sp).collect::<Vec<Span>>().into();
+            let msg = format!(
+                "{some} method{s} {are} available that return{r} `{ty}`",
+                some = if methods.len() == 1 { "a" } else { "some" },
+                s = pluralize!(methods.len()),
+                are = pluralize!("is", methods.len()),
+                r = if methods.len() == 1 { "s" } else { "" },
+                ty = expected
+            );
+            for (sp, label) in methods.into_iter() {
+                span.push_span_label(sp, label);
+            }
+            diag.span_help(span, &msg);
+            return true;
+        }
+        false
+    }
+
+    fn point_at_associated_type(
+        &self,
+        diag: &mut Diagnostic,
+        body_owner_def_id: DefId,
+        found: Ty<'tcx>,
+    ) -> bool {
+        let tcx = self.tcx;
+
+        let Some(hir_id) = body_owner_def_id.as_local() else {
+            return false;
+        };
+        let hir_id = tcx.hir().local_def_id_to_hir_id(hir_id);
+        // When `body_owner` is an `impl` or `trait` item, look in its associated types for
+        // `expected` and point at it.
+        let parent_id = tcx.hir().get_parent_item(hir_id);
+        let item = tcx.hir().find_by_def_id(parent_id.def_id);
+
+        debug!("expected_projection parent item {:?}", item);
+
+        let param_env = tcx.param_env(body_owner_def_id);
+
+        match item {
+            Some(hir::Node::Item(hir::Item { kind: hir::ItemKind::Trait(.., items), .. })) => {
+                // FIXME: account for `#![feature(specialization)]`
+                for item in &items[..] {
+                    match item.kind {
+                        hir::AssocItemKind::Type => {
+                            // FIXME: account for returning some type in a trait fn impl that has
+                            // an assoc type as a return type (#72076).
+                            if let hir::Defaultness::Default { has_value: true } =
+                                tcx.impl_defaultness(item.id.owner_id)
+                            {
+                                let assoc_ty = tcx.bound_type_of(item.id.owner_id).subst_identity();
+                                if self.infcx.can_eq(param_env, assoc_ty, found).is_ok() {
+                                    diag.span_label(
+                                        item.span,
+                                        "associated type defaults can't be assumed inside the \
+                                            trait defining them",
+                                    );
+                                    return true;
+                                }
+                            }
+                        }
+                        _ => {}
+                    }
+                }
+            }
+            Some(hir::Node::Item(hir::Item {
+                kind: hir::ItemKind::Impl(hir::Impl { items, .. }),
+                ..
+            })) => {
+                for item in &items[..] {
+                    if let hir::AssocItemKind::Type = item.kind {
+                        let assoc_ty = tcx.bound_type_of(item.id.owner_id).subst_identity();
+
+                        if self.infcx.can_eq(param_env, assoc_ty, found).is_ok() {
+                            diag.span_label(item.span, "expected this associated type");
+                            return true;
+                        }
+                    }
+                }
+            }
+            _ => {}
+        }
+        false
+    }
+
+    /// Given a slice of `hir::GenericBound`s, if any of them corresponds to the `trait_ref`
+    /// requirement, provide a structured suggestion to constrain it to a given type `ty`.
+    ///
+    /// `is_bound_surely_present` indicates whether we know the bound we're looking for is
+    /// inside `bounds`. If that's the case then we can consider `bounds` containing only one
+    /// trait bound as the one we're looking for. This can help in cases where the associated
+    /// type is defined on a supertrait of the one present in the bounds.
+    fn constrain_generic_bound_associated_type_structured_suggestion(
+        &self,
+        diag: &mut Diagnostic,
+        trait_ref: &ty::TraitRef<'tcx>,
+        bounds: hir::GenericBounds<'_>,
+        assoc: &ty::AssocItem,
+        assoc_substs: &[ty::GenericArg<'tcx>],
+        ty: Ty<'tcx>,
+        msg: &str,
+        is_bound_surely_present: bool,
+    ) -> bool {
+        // FIXME: we would want to call `resolve_vars_if_possible` on `ty` before suggesting.
+
+        let trait_bounds = bounds.iter().filter_map(|bound| match bound {
+            hir::GenericBound::Trait(ptr, hir::TraitBoundModifier::None) => Some(ptr),
+            _ => None,
+        });
+
+        let matching_trait_bounds = trait_bounds
+            .clone()
+            .filter(|ptr| ptr.trait_ref.trait_def_id() == Some(trait_ref.def_id))
+            .collect::<Vec<_>>();
+
+        let span = match &matching_trait_bounds[..] {
+            &[ptr] => ptr.span,
+            &[] if is_bound_surely_present => match &trait_bounds.collect::<Vec<_>>()[..] {
+                &[ptr] => ptr.span,
+                _ => return false,
+            },
+            _ => return false,
+        };
+
+        self.constrain_associated_type_structured_suggestion(
+            diag,
+            span,
+            assoc,
+            assoc_substs,
+            ty,
+            msg,
+        )
+    }
+
+    /// Given a span corresponding to a bound, provide a structured suggestion to set an
+    /// associated type to a given type `ty`.
+    fn constrain_associated_type_structured_suggestion(
+        &self,
+        diag: &mut Diagnostic,
+        span: Span,
+        assoc: &ty::AssocItem,
+        assoc_substs: &[ty::GenericArg<'tcx>],
+        ty: Ty<'tcx>,
+        msg: &str,
+    ) -> bool {
+        let tcx = self.tcx;
+
+        if let Ok(has_params) =
+            tcx.sess.source_map().span_to_snippet(span).map(|snippet| snippet.ends_with('>'))
+        {
+            let (span, sugg) = if has_params {
+                let pos = span.hi() - BytePos(1);
+                let span = Span::new(pos, pos, span.ctxt(), span.parent());
+                (span, format!(", {} = {}", assoc.ident(tcx), ty))
+            } else {
+                let item_args = self.format_generic_args(assoc_substs);
+                (span.shrink_to_hi(), format!("<{}{} = {}>", assoc.ident(tcx), item_args, ty))
+            };
+            diag.span_suggestion_verbose(span, msg, sugg, MaybeIncorrect);
+            return true;
+        }
+        false
+    }
+
+    pub fn format_generic_args(&self, args: &[ty::GenericArg<'tcx>]) -> String {
+        FmtPrinter::new(self.tcx, hir::def::Namespace::TypeNS)
+            .path_generic_args(Ok, args)
+            .expect("could not write to `String`.")
+            .into_buffer()
+    }
+}
index 5b02956a106c6cafa6775311a49921aafc355433..768cef89f3c439b2c61092d4bdcfa7a65ea5151b 100644 (file)
@@ -8,7 +8,7 @@
     StatementAsExpression,
 };
 use rustc_middle::ty::print::with_no_trimmed_paths;
-use rustc_middle::ty::{self as ty, Ty, TypeVisitable};
+use rustc_middle::ty::{self as ty, IsSuggestable, Ty, TypeVisitable};
 use rustc_span::{sym, BytePos, Span};
 
 use crate::errors::SuggAddLetForLetChains;
@@ -351,6 +351,118 @@ pub(super) fn suggest_as_ref_where_appropriate(
         }
     }
 
+    pub(super) fn suggest_function_pointers(
+        &self,
+        cause: &ObligationCause<'tcx>,
+        span: Span,
+        exp_found: &ty::error::ExpectedFound<Ty<'tcx>>,
+        diag: &mut Diagnostic,
+    ) {
+        debug!("suggest_function_pointers(cause={:?}, exp_found={:?})", cause, exp_found);
+        let ty::error::ExpectedFound { expected, found } = exp_found;
+        let expected_inner = expected.peel_refs();
+        let found_inner = found.peel_refs();
+        if !expected_inner.is_fn() || !found_inner.is_fn() {
+            return;
+        }
+        match (&expected_inner.kind(), &found_inner.kind()) {
+            (ty::FnPtr(sig), ty::FnDef(did, substs)) => {
+                let expected_sig = &(self.normalize_fn_sig)(*sig);
+                let found_sig =
+                    &(self.normalize_fn_sig)(self.tcx.bound_fn_sig(*did).subst(self.tcx, substs));
+
+                let fn_name = self.tcx.def_path_str_with_substs(*did, substs);
+
+                if !self.same_type_modulo_infer(*found_sig, *expected_sig)
+                    || !sig.is_suggestable(self.tcx, true)
+                    || ty::util::is_intrinsic(self.tcx, *did)
+                {
+                    return;
+                }
+
+                let (msg, sug) = match (expected.is_ref(), found.is_ref()) {
+                    (true, false) => {
+                        let msg = "consider using a reference";
+                        let sug = format!("&{fn_name}");
+                        (msg, sug)
+                    }
+                    (false, true) => {
+                        let msg = "consider removing the reference";
+                        let sug = format!("{fn_name}");
+                        (msg, sug)
+                    }
+                    (true, true) => {
+                        diag.note("fn items are distinct from fn pointers");
+                        let msg = "consider casting to a fn pointer";
+                        let sug = format!("&({fn_name} as {sig})");
+                        (msg, sug)
+                    }
+                    (false, false) => {
+                        diag.note("fn items are distinct from fn pointers");
+                        let msg = "consider casting to a fn pointer";
+                        let sug = format!("{fn_name} as {sig}");
+                        (msg, sug)
+                    }
+                };
+                diag.span_suggestion(span, msg, sug, Applicability::MaybeIncorrect);
+            }
+            (ty::FnDef(did1, substs1), ty::FnDef(did2, substs2)) => {
+                let expected_sig =
+                    &(self.normalize_fn_sig)(self.tcx.bound_fn_sig(*did1).subst(self.tcx, substs1));
+                let found_sig =
+                    &(self.normalize_fn_sig)(self.tcx.bound_fn_sig(*did2).subst(self.tcx, substs2));
+
+                if self.same_type_modulo_infer(*expected_sig, *found_sig) {
+                    diag.note("different fn items have unique types, even if their signatures are the same");
+                }
+
+                if !self.same_type_modulo_infer(*found_sig, *expected_sig)
+                    || !found_sig.is_suggestable(self.tcx, true)
+                    || !expected_sig.is_suggestable(self.tcx, true)
+                    || ty::util::is_intrinsic(self.tcx, *did1)
+                    || ty::util::is_intrinsic(self.tcx, *did2)
+                {
+                    return;
+                }
+
+                let fn_name = self.tcx.def_path_str_with_substs(*did2, substs2);
+                let sug = if found.is_ref() {
+                    format!("&({fn_name} as {found_sig})")
+                } else {
+                    format!("{fn_name} as {found_sig}")
+                };
+
+                let msg = format!(
+                    "consider casting both fn items to fn pointers using `as {expected_sig}`"
+                );
+
+                diag.span_suggestion_hidden(span, msg, sug, Applicability::MaybeIncorrect);
+            }
+            (ty::FnDef(did, substs), ty::FnPtr(sig)) => {
+                let expected_sig =
+                    &(self.normalize_fn_sig)(self.tcx.bound_fn_sig(*did).subst(self.tcx, substs));
+                let found_sig = &(self.normalize_fn_sig)(*sig);
+
+                if !self.same_type_modulo_infer(*found_sig, *expected_sig) {
+                    return;
+                }
+
+                let fn_name = self.tcx.def_path_str_with_substs(*did, substs);
+
+                let casting = if expected.is_ref() {
+                    format!("&({fn_name} as {found_sig})")
+                } else {
+                    format!("{fn_name} as {found_sig}")
+                };
+
+                diag.help(&format!("consider casting the fn item to a fn pointer: `{}`", casting));
+            }
+            _ => {
+                return;
+            }
+        };
+    }
+
     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())
@@ -411,8 +523,7 @@ pub(super) fn suggest_let_for_letchains(
         span: Span,
     ) {
         let hir = self.tcx.hir();
-        let fn_hir_id = hir.parent_id(cause.body_id);
-        if let Some(node) = self.tcx.hir().find(fn_hir_id) &&
+        if let Some(node) = self.tcx.hir().find_by_def_id(cause.body_id) &&
             let hir::Node::Item(hir::Item {
                     kind: hir::ItemKind::Fn(_sig, _, body_id), ..
                 }) = node {
index c54c66eab27998cdf0616e36d25404fdc417a143..b68b0baaa4062bd7df559e134fbb21b5b5725f49 100644 (file)
@@ -3,7 +3,7 @@
 use crate::traits;
 use hir::def::DefKind;
 use hir::def_id::{DefId, LocalDefId};
-use hir::{HirId, OpaqueTyOrigin};
+use hir::OpaqueTyOrigin;
 use rustc_data_structures::sync::Lrc;
 use rustc_data_structures::vec_map::VecMap;
 use rustc_hir as hir;
@@ -48,7 +48,7 @@ impl<'tcx> InferCtxt<'tcx> {
     pub fn replace_opaque_types_with_inference_vars<T: TypeFoldable<'tcx>>(
         &self,
         value: T,
-        body_id: HirId,
+        body_id: LocalDefId,
         span: Span,
         param_env: ty::ParamEnv<'tcx>,
     ) -> InferOk<'tcx, T> {
index 026713b6a28b8c539817d2362390f391f07533da..3a82899660b19df2e1c842cd7bb60a0624522358 100644 (file)
@@ -8,6 +8,7 @@
 mod structural_impls;
 pub mod util;
 
+use hir::def_id::LocalDefId;
 use rustc_hir as hir;
 use rustc_middle::ty::error::{ExpectedFound, TypeError};
 use rustc_middle::ty::{self, Const, ToPredicate, Ty, TyCtxt};
@@ -146,7 +147,7 @@ pub fn with_depth(
     pub fn misc(
         tcx: TyCtxt<'tcx>,
         span: Span,
-        body_id: hir::HirId,
+        body_id: LocalDefId,
         param_env: ty::ParamEnv<'tcx>,
         trait_ref: impl ToPredicate<'tcx, O>,
     ) -> Obligation<'tcx, O> {
index 379a76528f3bbba1d92aa19af21d0f15d8752d9d..37b381c534ea065c3a41e6ef3c4b2dd8d43ee225 100644 (file)
@@ -16,7 +16,7 @@
 use rustc_data_structures::sync::{Lrc, OnceCell, WorkerLocal};
 use rustc_errors::{ErrorGuaranteed, PResult};
 use rustc_expand::base::{ExtCtxt, LintStoreExpand, ResolverExpand};
-use rustc_hir::def_id::StableCrateId;
+use rustc_hir::def_id::{StableCrateId, LOCAL_CRATE};
 use rustc_lint::{BufferedEarlyLint, EarlyCheckNode, LintStore};
 use rustc_metadata::creader::CStore;
 use rustc_middle::arena::Arena;
@@ -30,7 +30,7 @@
 use rustc_query_impl::{OnDiskCache, Queries as TcxQueries};
 use rustc_resolve::{Resolver, ResolverArenas};
 use rustc_session::config::{CrateType, Input, OutputFilenames, OutputType};
-use rustc_session::cstore::{MetadataLoader, MetadataLoaderDyn, Untracked};
+use rustc_session::cstore::{CrateStoreDyn, MetadataLoader, MetadataLoaderDyn, Untracked};
 use rustc_session::output::filename_for_input;
 use rustc_session::search_paths::PathKind;
 use rustc_session::{Limit, Session};
@@ -47,7 +47,7 @@
 use std::path::{Path, PathBuf};
 use std::pin::Pin;
 use std::rc::Rc;
-use std::sync::LazyLock;
+use std::sync::{Arc, LazyLock};
 use std::{env, fs, iter};
 
 pub fn parse<'a>(sess: &'a Session) -> PResult<'a, ast::Crate> {
@@ -548,7 +548,7 @@ fn escape_dep_env(symbol: Symbol) -> String {
 
 fn write_out_deps(
     sess: &Session,
-    boxed_resolver: &RefCell<BoxedResolver>,
+    cstore: &CrateStoreDyn,
     outputs: &OutputFilenames,
     out_filenames: &[PathBuf],
 ) {
@@ -600,20 +600,19 @@ fn write_out_deps(
                 }
             }
 
-            boxed_resolver.borrow_mut().access(|resolver| {
-                for cnum in resolver.cstore().crates_untracked() {
-                    let source = resolver.cstore().crate_source_untracked(cnum);
-                    if let Some((path, _)) = &source.dylib {
-                        files.push(escape_dep_filename(&path.display().to_string()));
-                    }
-                    if let Some((path, _)) = &source.rlib {
-                        files.push(escape_dep_filename(&path.display().to_string()));
-                    }
-                    if let Some((path, _)) = &source.rmeta {
-                        files.push(escape_dep_filename(&path.display().to_string()));
-                    }
+            let cstore = cstore.as_any().downcast_ref::<CStore>().unwrap();
+            for cnum in cstore.crates_untracked() {
+                let source = cstore.crate_source_untracked(cnum);
+                if let Some((path, _)) = &source.dylib {
+                    files.push(escape_dep_filename(&path.display().to_string()));
                 }
-            });
+                if let Some((path, _)) = &source.rlib {
+                    files.push(escape_dep_filename(&path.display().to_string()));
+                }
+                if let Some((path, _)) = &source.rmeta {
+                    files.push(escape_dep_filename(&path.display().to_string()));
+                }
+            }
         }
 
         let mut file = BufWriter::new(fs::File::create(&deps_filename)?);
@@ -661,13 +660,11 @@ fn write_out_deps(
     }
 }
 
-pub fn prepare_outputs(
-    sess: &Session,
-    krate: &ast::Crate,
-    boxed_resolver: &RefCell<BoxedResolver>,
-    crate_name: Symbol,
-) -> Result<OutputFilenames> {
+fn output_filenames(tcx: TyCtxt<'_>, (): ()) -> Arc<OutputFilenames> {
+    let sess = tcx.sess;
     let _timer = sess.timer("prepare_outputs");
+    let (_, krate) = &*tcx.resolver_for_lowering(()).borrow();
+    let crate_name = tcx.crate_name(LOCAL_CRATE);
 
     // FIXME: rustdoc passes &[] instead of &krate.attrs here
     let outputs = util::build_output_filenames(&krate.attrs, sess);
@@ -679,25 +676,21 @@ pub fn prepare_outputs(
     if let Some(ref input_path) = sess.io.input.opt_path() {
         if sess.opts.will_create_output_file() {
             if output_contains_path(&output_paths, input_path) {
-                let reported = sess.emit_err(InputFileWouldBeOverWritten { path: input_path });
-                return Err(reported);
+                sess.emit_fatal(InputFileWouldBeOverWritten { path: input_path });
             }
             if let Some(ref dir_path) = output_conflicts_with_dir(&output_paths) {
-                let reported =
-                    sess.emit_err(GeneratedFileConflictsWithDirectory { input_path, dir_path });
-                return Err(reported);
+                sess.emit_fatal(GeneratedFileConflictsWithDirectory { input_path, dir_path });
             }
         }
     }
 
     if let Some(ref dir) = sess.io.temps_dir {
         if fs::create_dir_all(dir).is_err() {
-            let reported = sess.emit_err(TempsDirError);
-            return Err(reported);
+            sess.emit_fatal(TempsDirError);
         }
     }
 
-    write_out_deps(sess, boxed_resolver, &outputs, &output_paths);
+    write_out_deps(sess, tcx.cstore_untracked(), &outputs, &output_paths);
 
     let only_dep_info = sess.opts.output_types.contains_key(&OutputType::DepInfo)
         && sess.opts.output_types.len() == 1;
@@ -705,19 +698,19 @@ pub fn prepare_outputs(
     if !only_dep_info {
         if let Some(ref dir) = sess.io.output_dir {
             if fs::create_dir_all(dir).is_err() {
-                let reported = sess.emit_err(OutDirError);
-                return Err(reported);
+                sess.emit_fatal(OutDirError);
             }
         }
     }
 
-    Ok(outputs)
+    outputs.into()
 }
 
 pub static DEFAULT_QUERY_PROVIDERS: LazyLock<Providers> = LazyLock::new(|| {
     let providers = &mut Providers::default();
     providers.analysis = analysis;
     providers.hir_crate = rustc_ast_lowering::lower_to_hir;
+    providers.output_filenames = output_filenames;
     proc_macro_decls::provide(providers);
     rustc_const_eval::provide(providers);
     rustc_middle::hir::provide(providers);
index d5a49dd75be6a06bf7a7efa310342a139c15335b..4b0180741c19df0af11d84b6c6d388bc5b1ffc42 100644 (file)
@@ -65,7 +65,7 @@ fn deref_mut(&mut self) -> &mut Self::Target {
 }
 
 impl<'a, 'tcx> QueryResult<'a, QueryContext<'tcx>> {
-    pub fn enter<T>(mut self, f: impl FnOnce(TyCtxt<'tcx>) -> T) -> T {
+    pub fn enter<T>(&mut self, f: impl FnOnce(TyCtxt<'tcx>) -> T) -> T {
         (*self.0).get_mut().enter(f)
     }
 }
@@ -212,8 +212,6 @@ pub fn global_ctxt(&'tcx self) -> Result<QueryResult<'_, QueryContext<'tcx>>> {
             let crate_name = *self.crate_name()?.borrow();
             let (krate, resolver, lint_store) = self.expansion()?.steal();
 
-            let outputs = passes::prepare_outputs(self.session(), &krate, &resolver, crate_name)?;
-
             let ty::ResolverOutputs {
                 untracked,
                 global_ctxt: untracked_resolutions,
@@ -237,7 +235,6 @@ pub fn global_ctxt(&'tcx self) -> Result<QueryResult<'_, QueryContext<'tcx>>> {
                     tcx.arena.alloc(Steal::new((untracked_resolver_for_lowering, krate))),
                 );
                 feed.resolutions(tcx.arena.alloc(untracked_resolutions));
-                feed.output_filenames(tcx.arena.alloc(std::sync::Arc::new(outputs)));
                 feed.features_query(tcx.sess.features_untracked());
                 let feed = tcx.feed_local_crate();
                 feed.crate_name(crate_name);
index fe188162cf85bee0c694155f9abcc97057981e88..f27fd90c55c2a9527972be0ab8353705d7eff02d 100644 (file)
@@ -732,7 +732,7 @@ fn check_item(&mut self, cx: &LateContext<'_>, item: &hir::Item<'_>) {
             cx.tcx,
             param_env,
             ty,
-            traits::ObligationCause::misc(item.span, item.hir_id()),
+            traits::ObligationCause::misc(item.span, item.owner_id.def_id),
         )
         .is_ok()
         {
index 5219992ee94f0a76e4590bb0bebbe5508c029140..1add352e0c42d853f719a2db62c234b5497864ef 100644 (file)
@@ -139,9 +139,10 @@ fn suggest_question_mark<'tcx>(
 
     let ty = substs.type_at(0);
     let infcx = cx.tcx.infer_ctxt().build();
+    let body_def_id = cx.tcx.hir().body_owner_def_id(body_id);
     let cause = ObligationCause::new(
         span,
-        body_id.hir_id,
+        body_def_id,
         rustc_infer::traits::ObligationCauseCode::MiscObligation,
     );
     let errors = rustc_trait_selection::traits::fully_solve_bound(
index 44da3fbe300ca1cf4d4c167f1efb3c4a67df1e2c..bb2dd290c6d5d1edef0ef7f26ae3f0bbb1793d69 100644 (file)
@@ -985,7 +985,7 @@ fn get_mod_child(self, id: DefIndex, sess: &Session) -> ModChild {
         let vis = self.get_visibility(id);
         let span = self.get_span(id, sess);
         let macro_rules = match kind {
-            DefKind::Macro(..) => self.root.tables.macro_rules.get(self, id).is_some(),
+            DefKind::Macro(..) => self.root.tables.is_macro_rules.get(self, id),
             _ => false,
         };
 
@@ -1283,7 +1283,7 @@ fn exported_symbols(
     fn get_macro(self, id: DefIndex, sess: &Session) -> ast::MacroDef {
         match self.def_kind(id) {
             DefKind::Macro(_) => {
-                let macro_rules = self.root.tables.macro_rules.get(self, id).is_some();
+                let macro_rules = self.root.tables.is_macro_rules.get(self, id);
                 let body =
                     self.root.tables.macro_definition.get(self, id).unwrap().decode((self, sess));
                 ast::MacroDef { macro_rules, body: ast::ptr::P(body) }
@@ -1595,11 +1595,11 @@ fn get_generator_diagnostic_data(
     }
 
     fn get_attr_flags(self, index: DefIndex) -> AttrFlags {
-        self.root.tables.attr_flags.get(self, index).unwrap_or(AttrFlags::empty())
+        self.root.tables.attr_flags.get(self, index)
     }
 
     fn get_is_intrinsic(self, index: DefIndex) -> bool {
-        self.root.tables.is_intrinsic.get(self, index).is_some()
+        self.root.tables.is_intrinsic.get(self, index)
     }
 }
 
index 2fa645cd9e33de1a4dfdf1f31362ee26392cffaf..eebc2f21dfe4e8e4a79cc888f0aa41c8147d335e 100644 (file)
@@ -226,12 +226,7 @@ fn into_args(self) -> (DefId, SimplifiedType) {
     deduced_param_attrs => { table }
     is_type_alias_impl_trait => {
         debug_assert_eq!(tcx.def_kind(def_id), DefKind::OpaqueTy);
-        cdata
-            .root
-            .tables
-            .is_type_alias_impl_trait
-            .get(cdata, def_id.index)
-            .is_some()
+        cdata.root.tables.is_type_alias_impl_trait.get(cdata, def_id.index)
     }
     collect_return_position_impl_trait_in_trait_tys => {
         Ok(cdata
index 2ecaa33d4d315b604fb10bafd12345e923517652..29eba278750b1299c434d73570f05c518aab76eb 100644 (file)
@@ -38,7 +38,6 @@
 use rustc_span::{
     self, DebuggerVisualizerFile, ExternalSource, FileName, SourceFile, Span, SyntaxContext,
 };
-use rustc_target::abi::VariantIdx;
 use std::borrow::Borrow;
 use std::collections::hash_map::Entry;
 use std::hash::Hash;
@@ -483,7 +482,7 @@ fn encode_def_path_hash_map(&mut self) -> LazyValue<DefPathHashMapRef<'static>>
         self.lazy(DefPathHashMapRef::BorrowedFromTcx(self.tcx.def_path_hash_to_def_index_map()))
     }
 
-    fn encode_source_map(&mut self) -> LazyTable<u32, LazyValue<rustc_span::SourceFile>> {
+    fn encode_source_map(&mut self) -> LazyTable<u32, Option<LazyValue<rustc_span::SourceFile>>> {
         let source_map = self.tcx.sess.source_map();
         let all_source_files = source_map.files();
 
@@ -1130,7 +1129,7 @@ fn encode_attrs(&mut self, def_id: LocalDefId) {
             attr_flags |= AttrFlags::IS_DOC_HIDDEN;
         }
         if !attr_flags.is_empty() {
-            self.tables.attr_flags.set(def_id.local_def_index, attr_flags);
+            self.tables.attr_flags.set_nullable(def_id.local_def_index, attr_flags);
         }
     }
 
@@ -1189,8 +1188,7 @@ fn encode_def_ids(&mut self) {
                 record!(self.tables.super_predicates_of[def_id] <- self.tcx.super_predicates_of(def_id));
             }
             if let DefKind::Enum | DefKind::Struct | DefKind::Union = def_kind {
-                let params_in_repr = self.tcx.params_in_repr(def_id);
-                record!(self.tables.params_in_repr[def_id] <- params_in_repr);
+                self.encode_info_for_adt(def_id);
             }
             if should_encode_trait_impl_trait_tys(tcx, def_id)
                 && let Ok(table) = self.tcx.collect_return_position_impl_trait_in_trait_tys(def_id)
@@ -1213,46 +1211,53 @@ fn encode_def_ids(&mut self) {
         }
     }
 
-    fn encode_enum_variant_info(&mut self, def: ty::AdtDef<'tcx>, index: VariantIdx) {
+    #[instrument(level = "trace", skip(self))]
+    fn encode_info_for_adt(&mut self, def_id: DefId) {
         let tcx = self.tcx;
-        let variant = &def.variant(index);
-        let def_id = variant.def_id;
-        debug!("EncodeContext::encode_enum_variant_info({:?})", def_id);
-
-        let data = VariantData {
-            discr: variant.discr,
-            ctor: variant.ctor.map(|(kind, def_id)| (kind, def_id.index)),
-            is_non_exhaustive: variant.is_field_list_non_exhaustive(),
-        };
+        let adt_def = tcx.adt_def(def_id);
+        record!(self.tables.repr_options[def_id] <- adt_def.repr());
 
-        record!(self.tables.variant_data[def_id] <- data);
-        self.tables.constness.set(def_id.index, hir::Constness::Const);
-        record_array!(self.tables.children[def_id] <- variant.fields.iter().map(|f| {
-            assert!(f.did.is_local());
-            f.did.index
-        }));
-        if let Some((CtorKind::Fn, ctor_def_id)) = variant.ctor {
-            // FIXME(eddyb) encode signature only in `encode_enum_variant_ctor`.
-            record!(self.tables.fn_sig[def_id] <- tcx.fn_sig(ctor_def_id));
+        let params_in_repr = self.tcx.params_in_repr(def_id);
+        record!(self.tables.params_in_repr[def_id] <- params_in_repr);
+
+        if adt_def.is_enum() {
+            record_array!(self.tables.children[def_id] <- iter::from_generator(||
+                for variant in tcx.adt_def(def_id).variants() {
+                    yield variant.def_id.index;
+                    // Encode constructors which take a separate slot in value namespace.
+                    if let Some(ctor_def_id) = variant.ctor_def_id() {
+                        yield ctor_def_id.index;
+                    }
+                }
+            ));
+        } else {
+            // For non-enum, there is only one variant, and its def_id is the adt's.
+            debug_assert_eq!(adt_def.variants().len(), 1);
+            debug_assert_eq!(adt_def.non_enum_variant().def_id, def_id);
+            // Therefore, the loop over variants will encode its fields as the adt's children.
         }
-    }
 
-    fn encode_enum_variant_ctor(&mut self, def: ty::AdtDef<'tcx>, index: VariantIdx) {
-        let variant = &def.variant(index);
-        let Some((ctor_kind, def_id)) = variant.ctor else { return };
-        debug!("EncodeContext::encode_enum_variant_ctor({:?})", def_id);
+        for variant in adt_def.variants().iter() {
+            let data = VariantData {
+                discr: variant.discr,
+                ctor: variant.ctor.map(|(kind, def_id)| (kind, def_id.index)),
+                is_non_exhaustive: variant.is_field_list_non_exhaustive(),
+            };
+            record!(self.tables.variant_data[variant.def_id] <- data);
 
-        // FIXME(eddyb) encode only the `CtorKind` for constructors.
-        let data = VariantData {
-            discr: variant.discr,
-            ctor: Some((ctor_kind, def_id.index)),
-            is_non_exhaustive: variant.is_field_list_non_exhaustive(),
-        };
+            self.tables.constness.set(variant.def_id.index, hir::Constness::Const);
+            record_array!(self.tables.children[variant.def_id] <- variant.fields.iter().map(|f| {
+                assert!(f.did.is_local());
+                f.did.index
+            }));
 
-        record!(self.tables.variant_data[def_id] <- data);
-        self.tables.constness.set(def_id.index, hir::Constness::Const);
-        if ctor_kind == CtorKind::Fn {
-            record!(self.tables.fn_sig[def_id] <- self.tcx.fn_sig(def_id));
+            if let Some((CtorKind::Fn, ctor_def_id)) = variant.ctor {
+                self.tables.constness.set(ctor_def_id.index, hir::Constness::Const);
+                let fn_sig = tcx.fn_sig(ctor_def_id);
+                record!(self.tables.fn_sig[ctor_def_id] <- fn_sig);
+                // FIXME only encode signature for ctor_def_id
+                record!(self.tables.fn_sig[variant.def_id] <- fn_sig);
+            }
         }
     }
 
@@ -1305,25 +1310,6 @@ fn encode_info_for_mod(&mut self, local_def_id: LocalDefId, md: &hir::Mod<'_>) {
         }
     }
 
-    fn encode_struct_ctor(&mut self, adt_def: ty::AdtDef<'tcx>) {
-        let variant = adt_def.non_enum_variant();
-        let Some((ctor_kind, def_id)) = variant.ctor else { return };
-        debug!("EncodeContext::encode_struct_ctor({:?})", def_id);
-
-        let data = VariantData {
-            discr: variant.discr,
-            ctor: Some((ctor_kind, def_id.index)),
-            is_non_exhaustive: variant.is_field_list_non_exhaustive(),
-        };
-
-        record!(self.tables.repr_options[def_id] <- adt_def.repr());
-        record!(self.tables.variant_data[def_id] <- data);
-        self.tables.constness.set(def_id.index, hir::Constness::Const);
-        if ctor_kind == CtorKind::Fn {
-            record!(self.tables.fn_sig[def_id] <- self.tcx.fn_sig(def_id));
-        }
-    }
-
     fn encode_explicit_item_bounds(&mut self, def_id: DefId) {
         debug!("EncodeContext::encode_explicit_item_bounds({:?})", def_id);
         let bounds = self.tcx.explicit_item_bounds(def_id);
@@ -1387,7 +1373,7 @@ fn encode_info_for_impl_item(&mut self, def_id: DefId) {
         if impl_item.kind == ty::AssocKind::Fn {
             record!(self.tables.fn_sig[def_id] <- tcx.fn_sig(def_id));
             if tcx.is_intrinsic(def_id) {
-                self.tables.is_intrinsic.set(def_id.index, ());
+                self.tables.is_intrinsic.set_nullable(def_id.index, true);
             }
         }
     }
@@ -1519,7 +1505,7 @@ fn encode_info_for_item(&mut self, def_id: DefId, item: &'tcx hir::Item<'tcx>) {
             }
             hir::ItemKind::Macro(ref macro_def, _) => {
                 if macro_def.macro_rules {
-                    self.tables.macro_rules.set(def_id.index, ());
+                    self.tables.is_macro_rules.set_nullable(def_id.index, true);
                 }
                 record!(self.tables.macro_definition[def_id] <- &*macro_def.body);
             }
@@ -1529,36 +1515,9 @@ fn encode_info_for_item(&mut self, def_id: DefId, item: &'tcx hir::Item<'tcx>) {
             hir::ItemKind::OpaqueTy(ref opaque) => {
                 self.encode_explicit_item_bounds(def_id);
                 if matches!(opaque.origin, hir::OpaqueTyOrigin::TyAlias) {
-                    self.tables.is_type_alias_impl_trait.set(def_id.index, ());
+                    self.tables.is_type_alias_impl_trait.set_nullable(def_id.index, true);
                 }
             }
-            hir::ItemKind::Enum(..) => {
-                let adt_def = self.tcx.adt_def(def_id);
-                record!(self.tables.repr_options[def_id] <- adt_def.repr());
-            }
-            hir::ItemKind::Struct(..) => {
-                let adt_def = self.tcx.adt_def(def_id);
-                record!(self.tables.repr_options[def_id] <- adt_def.repr());
-                self.tables.constness.set(def_id.index, hir::Constness::Const);
-
-                let variant = adt_def.non_enum_variant();
-                record!(self.tables.variant_data[def_id] <- VariantData {
-                    discr: variant.discr,
-                    ctor: variant.ctor.map(|(kind, def_id)| (kind, def_id.index)),
-                    is_non_exhaustive: variant.is_field_list_non_exhaustive(),
-                });
-            }
-            hir::ItemKind::Union(..) => {
-                let adt_def = self.tcx.adt_def(def_id);
-                record!(self.tables.repr_options[def_id] <- adt_def.repr());
-
-                let variant = adt_def.non_enum_variant();
-                record!(self.tables.variant_data[def_id] <- VariantData {
-                    discr: variant.discr,
-                    ctor: variant.ctor.map(|(kind, def_id)| (kind, def_id.index)),
-                    is_non_exhaustive: variant.is_field_list_non_exhaustive(),
-                });
-            }
             hir::ItemKind::Impl(hir::Impl { defaultness, constness, .. }) => {
                 self.tables.impl_defaultness.set(def_id.index, *defaultness);
                 self.tables.constness.set(def_id.index, *constness);
@@ -1597,31 +1556,15 @@ fn encode_info_for_item(&mut self, def_id: DefId, item: &'tcx hir::Item<'tcx>) {
             }
             hir::ItemKind::Static(..)
             | hir::ItemKind::Const(..)
+            | hir::ItemKind::Enum(..)
+            | hir::ItemKind::Struct(..)
+            | hir::ItemKind::Union(..)
             | hir::ItemKind::ForeignMod { .. }
             | hir::ItemKind::GlobalAsm(..)
             | hir::ItemKind::TyAlias(..) => {}
         };
         // FIXME(eddyb) there should be a nicer way to do this.
         match item.kind {
-            hir::ItemKind::Enum(..) => {
-                record_array!(self.tables.children[def_id] <- iter::from_generator(||
-                    for variant in tcx.adt_def(def_id).variants() {
-                        yield variant.def_id.index;
-                        // Encode constructors which take a separate slot in value namespace.
-                        if let Some(ctor_def_id) = variant.ctor_def_id() {
-                            yield ctor_def_id.index;
-                        }
-                    }
-                ))
-            }
-            hir::ItemKind::Struct(..) | hir::ItemKind::Union(..) => {
-                record_array!(self.tables.children[def_id] <-
-                    self.tcx.adt_def(def_id).non_enum_variant().fields.iter().map(|f| {
-                        assert!(f.did.is_local());
-                        f.did.index
-                    })
-                )
-            }
             hir::ItemKind::Impl { .. } | hir::ItemKind::Trait(..) => {
                 let associated_item_def_ids = self.tcx.associated_item_def_ids(def_id);
                 record_array!(self.tables.children[def_id] <-
@@ -1636,7 +1579,7 @@ fn encode_info_for_item(&mut self, def_id: DefId, item: &'tcx hir::Item<'tcx>) {
         if let hir::ItemKind::Fn(..) = item.kind {
             record!(self.tables.fn_sig[def_id] <- tcx.fn_sig(def_id));
             if tcx.is_intrinsic(def_id) {
-                self.tables.is_intrinsic.set(def_id.index, ());
+                self.tables.is_intrinsic.set_nullable(def_id.index, true);
             }
         }
         if let hir::ItemKind::Impl { .. } = item.kind {
@@ -1649,17 +1592,6 @@ fn encode_info_for_item(&mut self, def_id: DefId, item: &'tcx hir::Item<'tcx>) {
         // so it's easier to do that here then to wait until we would encounter
         // normally in the visitor walk.
         match item.kind {
-            hir::ItemKind::Enum(..) => {
-                let def = self.tcx.adt_def(item.owner_id.to_def_id());
-                for (i, _) in def.variants().iter_enumerated() {
-                    self.encode_enum_variant_info(def, i);
-                    self.encode_enum_variant_ctor(def, i);
-                }
-            }
-            hir::ItemKind::Struct(..) => {
-                let def = self.tcx.adt_def(item.owner_id.to_def_id());
-                self.encode_struct_ctor(def);
-            }
             hir::ItemKind::Impl { .. } => {
                 for &trait_item_def_id in
                     self.tcx.associated_item_def_ids(item.owner_id.to_def_id()).iter()
@@ -2038,7 +1970,7 @@ fn encode_info_for_foreign_item(&mut self, def_id: DefId, nitem: &hir::ForeignIt
         }
         if let hir::ForeignItemKind::Fn(..) = nitem.kind {
             if tcx.is_intrinsic(def_id) {
-                self.tables.is_intrinsic.set(def_id.index, ());
+                self.tables.is_intrinsic.set_nullable(def_id.index, true);
             }
         }
     }
index 69690264ae4ea5e96d7ffd1642d322028effd3ef..698b2ebc4732a0d0d66c60bc8a1277b973a30b46 100644 (file)
@@ -185,9 +185,9 @@ enum LazyState {
     Previous(NonZeroUsize),
 }
 
-type SyntaxContextTable = LazyTable<u32, LazyValue<SyntaxContextData>>;
-type ExpnDataTable = LazyTable<ExpnIndex, LazyValue<ExpnData>>;
-type ExpnHashTable = LazyTable<ExpnIndex, LazyValue<ExpnHash>>;
+type SyntaxContextTable = LazyTable<u32, Option<LazyValue<SyntaxContextData>>>;
+type ExpnDataTable = LazyTable<ExpnIndex, Option<LazyValue<ExpnData>>>;
+type ExpnHashTable = LazyTable<ExpnIndex, Option<LazyValue<ExpnHash>>>;
 
 #[derive(MetadataEncodable, MetadataDecodable)]
 pub(crate) struct ProcMacroData {
@@ -253,7 +253,7 @@ pub(crate) struct CrateRoot {
 
     def_path_hash_map: LazyValue<DefPathHashMapRef<'static>>,
 
-    source_map: LazyTable<u32, LazyValue<rustc_span::SourceFile>>,
+    source_map: LazyTable<u32, Option<LazyValue<rustc_span::SourceFile>>>,
 
     compiler_builtins: bool,
     needs_allocator: bool,
@@ -315,21 +315,27 @@ pub(crate) struct IncoherentImpls {
 
 /// Define `LazyTables` and `TableBuilders` at the same time.
 macro_rules! define_tables {
-    ($($name:ident: Table<$IDX:ty, $T:ty>),+ $(,)?) => {
+    (
+        - nullable: $($name1:ident: Table<$IDX1:ty, $T1:ty>,)+
+        - optional: $($name2:ident: Table<$IDX2:ty, $T2:ty>,)+
+    ) => {
         #[derive(MetadataEncodable, MetadataDecodable)]
         pub(crate) struct LazyTables {
-            $($name: LazyTable<$IDX, $T>),+
+            $($name1: LazyTable<$IDX1, $T1>,)+
+            $($name2: LazyTable<$IDX2, Option<$T2>>,)+
         }
 
         #[derive(Default)]
         struct TableBuilders {
-            $($name: TableBuilder<$IDX, $T>),+
+            $($name1: TableBuilder<$IDX1, $T1>,)+
+            $($name2: TableBuilder<$IDX2, Option<$T2>>,)+
         }
 
         impl TableBuilders {
             fn encode(&self, buf: &mut FileEncoder) -> LazyTables {
                 LazyTables {
-                    $($name: self.$name.encode(buf)),+
+                    $($name1: self.$name1.encode(buf),)+
+                    $($name2: self.$name2.encode(buf),)+
                 }
             }
         }
@@ -337,9 +343,15 @@ fn encode(&self, buf: &mut FileEncoder) -> LazyTables {
 }
 
 define_tables! {
+- nullable:
+    is_intrinsic: Table<DefIndex, bool>,
+    is_macro_rules: Table<DefIndex, bool>,
+    is_type_alias_impl_trait: Table<DefIndex, bool>,
+    attr_flags: Table<DefIndex, AttrFlags>,
+
+- optional:
     attributes: Table<DefIndex, LazyArray<ast::Attribute>>,
     children: Table<DefIndex, LazyArray<DefIndex>>,
-
     opt_def_kind: Table<DefIndex, DefKind>,
     visibility: Table<DefIndex, LazyValue<ty::Visibility<DefIndex>>>,
     def_span: Table<DefIndex, LazyValue<Span>>,
@@ -370,7 +382,6 @@ fn encode(&self, buf: &mut FileEncoder) -> LazyTables {
     impl_parent: Table<DefIndex, RawDefId>,
     impl_polarity: Table<DefIndex, ty::ImplPolarity>,
     constness: Table<DefIndex, hir::Constness>,
-    is_intrinsic: Table<DefIndex, ()>,
     impl_defaultness: Table<DefIndex, hir::Defaultness>,
     // FIXME(eddyb) perhaps compute this on the fly if cheap enough?
     coerce_unsized_info: Table<DefIndex, LazyValue<ty::adjustment::CoerceUnsizedInfo>>,
@@ -380,7 +391,6 @@ fn encode(&self, buf: &mut FileEncoder) -> LazyTables {
     fn_arg_names: Table<DefIndex, LazyArray<Ident>>,
     generator_kind: Table<DefIndex, LazyValue<hir::GeneratorKind>>,
     trait_def: Table<DefIndex, LazyValue<ty::TraitDef>>,
-
     trait_item_def_id: Table<DefIndex, RawDefId>,
     inherent_impls: Table<DefIndex, LazyArray<DefIndex>>,
     expn_that_defined: Table<DefIndex, LazyValue<ExpnId>>,
@@ -395,18 +405,12 @@ fn encode(&self, buf: &mut FileEncoder) -> LazyTables {
     def_path_hashes: Table<DefIndex, DefPathHash>,
     proc_macro_quoted_spans: Table<usize, LazyValue<Span>>,
     generator_diagnostic_data: Table<DefIndex, LazyValue<GeneratorDiagnosticData<'static>>>,
-    attr_flags: Table<DefIndex, AttrFlags>,
     variant_data: Table<DefIndex, LazyValue<VariantData>>,
     assoc_container: Table<DefIndex, ty::AssocItemContainer>,
-    // Slot is full when macro is macro_rules.
-    macro_rules: Table<DefIndex, ()>,
     macro_definition: Table<DefIndex, LazyValue<ast::DelimArgs>>,
     proc_macro: Table<DefIndex, MacroKind>,
     module_reexports: Table<DefIndex, LazyArray<ModChild>>,
     deduced_param_attrs: Table<DefIndex, LazyArray<DeducedParamAttrs>>,
-    // Slot is full when opaque is TAIT.
-    is_type_alias_impl_trait: Table<DefIndex, ()>,
-
     trait_impl_trait_tys: Table<DefIndex, LazyValue<FxHashMap<DefId, Ty<'static>>>>,
 }
 
@@ -419,6 +423,7 @@ struct VariantData {
 }
 
 bitflags::bitflags! {
+    #[derive(Default)]
     pub struct AttrFlags: u8 {
         const MAY_HAVE_DOC_LINKS = 1 << 0;
         const IS_DOC_HIDDEN      = 1 << 1;
index dc003227d40bd1d63ff84d2d245d196524776029..70dbf6476e2fab40d8c4a89b575528b3bd3f6f6b 100644 (file)
@@ -16,6 +16,7 @@
 /// but this has no impact on safety.
 pub(super) trait FixedSizeEncoding: Default {
     /// This should be `[u8; BYTE_LEN]`;
+    /// Cannot use an associated `const BYTE_LEN: usize` instead due to const eval limitations.
     type ByteArray;
 
     fn from_bytes(b: &Self::ByteArray) -> Self;
@@ -199,31 +200,31 @@ impl FixedSizeEncoding for Option<RawDefId> {
     }
 }
 
-impl FixedSizeEncoding for Option<AttrFlags> {
+impl FixedSizeEncoding for AttrFlags {
     type ByteArray = [u8; 1];
 
     #[inline]
     fn from_bytes(b: &[u8; 1]) -> Self {
-        (b[0] != 0).then(|| AttrFlags::from_bits_truncate(b[0]))
+        AttrFlags::from_bits_truncate(b[0])
     }
 
     #[inline]
     fn write_to_bytes(self, b: &mut [u8; 1]) {
-        b[0] = self.map_or(0, |flags| flags.bits())
+        b[0] = self.bits();
     }
 }
 
-impl FixedSizeEncoding for Option<()> {
+impl FixedSizeEncoding for bool {
     type ByteArray = [u8; 1];
 
     #[inline]
     fn from_bytes(b: &[u8; 1]) -> Self {
-        (b[0] != 0).then(|| ())
+        b[0] != 0
     }
 
     #[inline]
     fn write_to_bytes(self, b: &mut [u8; 1]) {
-        b[0] = self.is_some() as u8
+        b[0] = self as u8
     }
 }
 
@@ -273,44 +274,38 @@ impl<T> FixedSizeEncoding for Option<LazyArray<T>> {
 }
 
 /// Helper for constructing a table's serialization (also see `Table`).
-pub(super) struct TableBuilder<I: Idx, T>
-where
-    Option<T>: FixedSizeEncoding,
-{
-    blocks: IndexVec<I, <Option<T> as FixedSizeEncoding>::ByteArray>,
+pub(super) struct TableBuilder<I: Idx, T: FixedSizeEncoding> {
+    blocks: IndexVec<I, T::ByteArray>,
     _marker: PhantomData<T>,
 }
 
-impl<I: Idx, T> Default for TableBuilder<I, T>
-where
-    Option<T>: FixedSizeEncoding,
-{
+impl<I: Idx, T: FixedSizeEncoding> Default for TableBuilder<I, T> {
     fn default() -> Self {
         TableBuilder { blocks: Default::default(), _marker: PhantomData }
     }
 }
 
-impl<I: Idx, T> TableBuilder<I, T>
+impl<I: Idx, const N: usize, T> TableBuilder<I, Option<T>>
 where
-    Option<T>: FixedSizeEncoding,
+    Option<T>: FixedSizeEncoding<ByteArray = [u8; N]>,
 {
-    pub(crate) fn set<const N: usize>(&mut self, i: I, value: T)
-    where
-        Option<T>: FixedSizeEncoding<ByteArray = [u8; N]>,
-    {
+    pub(crate) fn set(&mut self, i: I, value: T) {
+        self.set_nullable(i, Some(value))
+    }
+}
+
+impl<I: Idx, const N: usize, T: FixedSizeEncoding<ByteArray = [u8; N]>> TableBuilder<I, T> {
+    pub(crate) fn set_nullable(&mut self, i: I, value: T) {
         // FIXME(eddyb) investigate more compact encodings for sparse tables.
         // On the PR @michaelwoerister mentioned:
         // > Space requirements could perhaps be optimized by using the HAMT `popcnt`
         // > trick (i.e. divide things into buckets of 32 or 64 items and then
         // > store bit-masks of which item in each bucket is actually serialized).
         self.blocks.ensure_contains_elem(i, || [0; N]);
-        Some(value).write_to_bytes(&mut self.blocks[i]);
+        value.write_to_bytes(&mut self.blocks[i]);
     }
 
-    pub(crate) fn encode<const N: usize>(&self, buf: &mut FileEncoder) -> LazyTable<I, T>
-    where
-        Option<T>: FixedSizeEncoding<ByteArray = [u8; N]>,
-    {
+    pub(crate) fn encode(&self, buf: &mut FileEncoder) -> LazyTable<I, T> {
         let pos = buf.position();
         for block in &self.blocks {
             buf.emit_raw_bytes(block);
@@ -323,34 +318,27 @@ pub(crate) fn encode<const N: usize>(&self, buf: &mut FileEncoder) -> LazyTable<
     }
 }
 
-impl<I: Idx, T: ParameterizedOverTcx> LazyTable<I, T>
+impl<I: Idx, const N: usize, T: FixedSizeEncoding<ByteArray = [u8; N]> + ParameterizedOverTcx>
+    LazyTable<I, T>
 where
-    Option<T>: FixedSizeEncoding,
+    for<'tcx> T::Value<'tcx>: FixedSizeEncoding<ByteArray = [u8; N]>,
 {
     /// Given the metadata, extract out the value at a particular index (if any).
     #[inline(never)]
-    pub(super) fn get<'a, 'tcx, M: Metadata<'a, 'tcx>, const N: usize>(
-        &self,
-        metadata: M,
-        i: I,
-    ) -> Option<T::Value<'tcx>>
-    where
-        Option<T::Value<'tcx>>: FixedSizeEncoding<ByteArray = [u8; N]>,
-    {
+    pub(super) fn get<'a, 'tcx, M: Metadata<'a, 'tcx>>(&self, metadata: M, i: I) -> T::Value<'tcx> {
         debug!("LazyTable::lookup: index={:?} len={:?}", i, self.encoded_size);
 
         let start = self.position.get();
         let bytes = &metadata.blob()[start..start + self.encoded_size];
         let (bytes, []) = bytes.as_chunks::<N>() else { panic!() };
-        let bytes = bytes.get(i.index())?;
-        FixedSizeEncoding::from_bytes(bytes)
+        match bytes.get(i.index()) {
+            Some(bytes) => FixedSizeEncoding::from_bytes(bytes),
+            None => FixedSizeEncoding::from_bytes(&[0; N]),
+        }
     }
 
     /// Size of the table in entries, including possible gaps.
-    pub(super) fn size<const N: usize>(&self) -> usize
-    where
-        for<'tcx> Option<T::Value<'tcx>>: FixedSizeEncoding<ByteArray = [u8; N]>,
-    {
+    pub(super) fn size(&self) -> usize {
         self.encoded_size / N
     }
 }
index 7e4063c2ffd78fb0f0f2280dbcfade275fce56ad..95148de251824ad0aceb5dbe48777fcbceaeddbc 100644 (file)
@@ -43,6 +43,7 @@
 #![feature(min_specialization)]
 #![feature(trusted_len)]
 #![feature(type_alias_impl_trait)]
+#![feature(strict_provenance)]
 #![feature(associated_type_bounds)]
 #![feature(rustc_attrs)]
 #![feature(control_flow_enum)]
index 5f425a287687e60a562e446be171d156c959ebae..b0975616b6151546773253fb88af57da891f678f 100644 (file)
@@ -110,7 +110,7 @@ macro_rules! throw_machine_stop {
 use rustc_macros::HashStable;
 use rustc_middle::ty::print::with_no_trimmed_paths;
 use rustc_serialize::{Decodable, Encodable};
-use rustc_target::abi::Endian;
+use rustc_target::abi::{AddressSpace, Endian, HasDataLayout};
 
 use crate::mir;
 use crate::ty::codec::{TyDecoder, TyEncoder};
@@ -438,6 +438,17 @@ pub fn unwrap_vtable(&self) -> (Ty<'tcx>, Option<ty::PolyExistentialTraitRef<'tc
             _ => bug!("expected vtable, got {:?}", self),
         }
     }
+
+    /// The address space that this `GlobalAlloc` should be placed in.
+    #[inline]
+    pub fn address_space(&self, cx: &impl HasDataLayout) -> AddressSpace {
+        match self {
+            GlobalAlloc::Function(..) => cx.data_layout().instruction_address_space,
+            GlobalAlloc::Static(..) | GlobalAlloc::Memory(..) | GlobalAlloc::VTable(..) => {
+                AddressSpace::DATA
+            }
+        }
+    }
 }
 
 pub(crate) struct AllocMap<'tcx> {
index 7db86c8d0d4545f355f1b94f7734c713883dbbc9..2e5261331e8be1e782a58d88d78ef2a593a97279 100644 (file)
     ///
     /// This query returns an `&Arc` because codegen backends need the value even after the `TyCtxt`
     /// has been destroyed.
-    query output_filenames(_: ()) -> &'tcx Arc<OutputFilenames> {
+    query output_filenames(_: ()) -> Arc<OutputFilenames> {
         feedable
         desc { "getting output filenames" }
+        arena_cache
     }
 
     /// Do not call this query directly: invoke `normalize` instead.
         separate_provide_extern
     }
 
-    query permits_uninit_init(key: TyAndLayout<'tcx>) -> bool {
-        desc { "checking to see if `{}` permits being left uninit", key.ty }
+    query permits_uninit_init(key: ty::ParamEnvAnd<'tcx, TyAndLayout<'tcx>>) -> bool {
+        desc { "checking to see if `{}` permits being left uninit", key.value.ty }
     }
 
-    query permits_zero_init(key: TyAndLayout<'tcx>) -> bool {
-        desc { "checking to see if `{}` permits being left zeroed", key.ty }
+    query permits_zero_init(key: ty::ParamEnvAnd<'tcx, TyAndLayout<'tcx>>) -> bool {
+        desc { "checking to see if `{}` permits being left zeroed", key.value.ty }
     }
 
     query compare_impl_const(
index d00b26a5a3d0b42baafca1d795332bbfc0ddbdcc..f6fae8ab552743c23007da3bd119e93ff8e21ad9 100644 (file)
@@ -18,7 +18,8 @@
 use rustc_data_structures::sync::Lrc;
 use rustc_errors::{Applicability, Diagnostic};
 use rustc_hir as hir;
-use rustc_hir::def_id::{DefId, LocalDefId};
+use rustc_hir::def_id::DefId;
+use rustc_span::def_id::{LocalDefId, CRATE_DEF_ID};
 use rustc_span::symbol::Symbol;
 use rustc_span::{Span, DUMMY_SP};
 use smallvec::SmallVec;
@@ -99,7 +100,7 @@ pub struct ObligationCause<'tcx> {
     /// (in particular, closures can add new assumptions). See the
     /// field `region_obligations` of the `FulfillmentContext` for more
     /// information.
-    pub body_id: hir::HirId,
+    pub body_id: LocalDefId,
 
     code: InternedObligationCauseCode<'tcx>,
 }
@@ -120,13 +121,13 @@ impl<'tcx> ObligationCause<'tcx> {
     #[inline]
     pub fn new(
         span: Span,
-        body_id: hir::HirId,
+        body_id: LocalDefId,
         code: ObligationCauseCode<'tcx>,
     ) -> ObligationCause<'tcx> {
         ObligationCause { span, body_id, code: code.into() }
     }
 
-    pub fn misc(span: Span, body_id: hir::HirId) -> ObligationCause<'tcx> {
+    pub fn misc(span: Span, body_id: LocalDefId) -> ObligationCause<'tcx> {
         ObligationCause::new(span, body_id, MiscObligation)
     }
 
@@ -137,7 +138,7 @@ pub fn dummy() -> ObligationCause<'tcx> {
 
     #[inline(always)]
     pub fn dummy_with_span(span: Span) -> ObligationCause<'tcx> {
-        ObligationCause { span, body_id: hir::CRATE_HIR_ID, code: Default::default() }
+        ObligationCause { span, body_id: CRATE_DEF_ID, code: Default::default() }
     }
 
     pub fn span(&self) -> Span {
index bb7fba3ee7119ad9c00af8c9f4311bfd4d5c11b2..47091ca1d69a719ce275a439356088f890294d10 100644 (file)
@@ -130,7 +130,7 @@ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 /// done only on items with the same name.
 #[derive(Debug, Clone, PartialEq, HashStable)]
 pub struct AssocItems<'tcx> {
-    pub(super) items: SortedIndexMultiMap<u32, Symbol, &'tcx ty::AssocItem>,
+    items: SortedIndexMultiMap<u32, Symbol, &'tcx ty::AssocItem>,
 }
 
 impl<'tcx> AssocItems<'tcx> {
index ce04d8d21f4cdf2e4255d13faccc98f781d61681..a60c55e8af4d2305571698677e720600568596a1 100644 (file)
@@ -2,6 +2,8 @@
 
 #![allow(rustc::usage_of_ty_tykind)]
 
+pub mod tls;
+
 use crate::arena::Arena;
 use crate::dep_graph::{DepGraph, DepKindStruct};
 use crate::infer::canonical::{CanonicalVarInfo, CanonicalVarInfos};
@@ -997,6 +999,30 @@ pub fn return_type_impl_or_dyn_traits(
         v.0
     }
 
+    /// Given a `DefId` for an `fn`, return all the `dyn` and `impl` traits in its return type and associated alias span when type alias is used
+    pub fn return_type_impl_or_dyn_traits_with_type_alias(
+        self,
+        scope_def_id: LocalDefId,
+    ) -> Option<(Vec<&'tcx hir::Ty<'tcx>>, Span)> {
+        let hir_id = self.hir().local_def_id_to_hir_id(scope_def_id);
+        let mut v = TraitObjectVisitor(vec![], self.hir());
+        // when the return type is a type alias
+        if let Some(hir::FnDecl { output: hir::FnRetTy::Return(hir_output), .. }) = self.hir().fn_decl_by_hir_id(hir_id)
+            && let hir::TyKind::Path(hir::QPath::Resolved(
+                None,
+                hir::Path { res: hir::def::Res::Def(DefKind::TyAlias, def_id), .. }, )) = hir_output.kind
+            && let Some(local_id) = def_id.as_local()
+            && let Some(alias_ty) = self.hir().get_by_def_id(local_id).alias_ty() // it is type alias
+            && let Some(alias_generics) = self.hir().get_by_def_id(local_id).generics()
+        {
+            v.visit_ty(alias_ty);
+            if !v.0.is_empty() {
+                return Some((v.0, alias_generics.span));
+            }
+        }
+        return None;
+    }
+
     pub fn return_type_impl_trait(self, scope_def_id: LocalDefId) -> Option<(Ty<'tcx>, Span)> {
         // `type_of()` will fail on these (#55796, #86483), so only allow `fn`s or closures.
         match self.hir().get_by_def_id(scope_def_id) {
@@ -1188,178 +1214,6 @@ fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
     Constness, traits::WellFormedLoc, ImplPolarity, crate::mir::ReturnConstraint,
 } }
 
-pub mod tls {
-    use super::{ptr_eq, GlobalCtxt, TyCtxt};
-
-    use crate::dep_graph::TaskDepsRef;
-    use crate::ty::query;
-    use rustc_data_structures::sync::{self, Lock};
-    use rustc_errors::Diagnostic;
-    use std::mem;
-    use thin_vec::ThinVec;
-
-    #[cfg(not(parallel_compiler))]
-    use std::cell::Cell;
-
-    #[cfg(parallel_compiler)]
-    use rustc_rayon_core as rayon_core;
-
-    /// This is the implicit state of rustc. It contains the current
-    /// `TyCtxt` and query. It is updated when creating a local interner or
-    /// executing a new query. Whenever there's a `TyCtxt` value available
-    /// you should also have access to an `ImplicitCtxt` through the functions
-    /// in this module.
-    #[derive(Clone)]
-    pub struct ImplicitCtxt<'a, 'tcx> {
-        /// The current `TyCtxt`.
-        pub tcx: TyCtxt<'tcx>,
-
-        /// The current query job, if any. This is updated by `JobOwner::start` in
-        /// `ty::query::plumbing` when executing a query.
-        pub query: Option<query::QueryJobId>,
-
-        /// Where to store diagnostics for the current query job, if any.
-        /// This is updated by `JobOwner::start` in `ty::query::plumbing` when executing a query.
-        pub diagnostics: Option<&'a Lock<ThinVec<Diagnostic>>>,
-
-        /// Used to prevent queries from calling too deeply.
-        pub query_depth: usize,
-
-        /// The current dep graph task. This is used to add dependencies to queries
-        /// when executing them.
-        pub task_deps: TaskDepsRef<'a>,
-    }
-
-    impl<'a, 'tcx> ImplicitCtxt<'a, 'tcx> {
-        pub fn new(gcx: &'tcx GlobalCtxt<'tcx>) -> Self {
-            let tcx = TyCtxt { gcx };
-            ImplicitCtxt {
-                tcx,
-                query: None,
-                diagnostics: None,
-                query_depth: 0,
-                task_deps: TaskDepsRef::Ignore,
-            }
-        }
-    }
-
-    /// Sets Rayon's thread-local variable, which is preserved for Rayon jobs
-    /// to `value` during the call to `f`. It is restored to its previous value after.
-    /// This is used to set the pointer to the new `ImplicitCtxt`.
-    #[cfg(parallel_compiler)]
-    #[inline]
-    fn set_tlv<F: FnOnce() -> R, R>(value: usize, f: F) -> R {
-        rayon_core::tlv::with(value, f)
-    }
-
-    /// Gets Rayon's thread-local variable, which is preserved for Rayon jobs.
-    /// This is used to get the pointer to the current `ImplicitCtxt`.
-    #[cfg(parallel_compiler)]
-    #[inline]
-    pub fn get_tlv() -> usize {
-        rayon_core::tlv::get()
-    }
-
-    #[cfg(not(parallel_compiler))]
-    thread_local! {
-        /// A thread local variable that stores a pointer to the current `ImplicitCtxt`.
-        static TLV: Cell<usize> = const { Cell::new(0) };
-    }
-
-    /// Sets TLV to `value` during the call to `f`.
-    /// It is restored to its previous value after.
-    /// This is used to set the pointer to the new `ImplicitCtxt`.
-    #[cfg(not(parallel_compiler))]
-    #[inline]
-    fn set_tlv<F: FnOnce() -> R, R>(value: usize, f: F) -> R {
-        let old = get_tlv();
-        let _reset = rustc_data_structures::OnDrop(move || TLV.with(|tlv| tlv.set(old)));
-        TLV.with(|tlv| tlv.set(value));
-        f()
-    }
-
-    /// Gets the pointer to the current `ImplicitCtxt`.
-    #[cfg(not(parallel_compiler))]
-    #[inline]
-    fn get_tlv() -> usize {
-        TLV.with(|tlv| tlv.get())
-    }
-
-    /// Sets `context` as the new current `ImplicitCtxt` for the duration of the function `f`.
-    #[inline]
-    pub fn enter_context<'a, 'tcx, F, R>(context: &ImplicitCtxt<'a, 'tcx>, f: F) -> R
-    where
-        F: FnOnce(&ImplicitCtxt<'a, 'tcx>) -> R,
-    {
-        set_tlv(context as *const _ as usize, || f(&context))
-    }
-
-    /// Allows access to the current `ImplicitCtxt` in a closure if one is available.
-    #[inline]
-    pub fn with_context_opt<F, R>(f: F) -> R
-    where
-        F: for<'a, 'tcx> FnOnce(Option<&ImplicitCtxt<'a, 'tcx>>) -> R,
-    {
-        let context = get_tlv();
-        if context == 0 {
-            f(None)
-        } else {
-            // We could get an `ImplicitCtxt` pointer from another thread.
-            // Ensure that `ImplicitCtxt` is `Sync`.
-            sync::assert_sync::<ImplicitCtxt<'_, '_>>();
-
-            unsafe { f(Some(&*(context as *const ImplicitCtxt<'_, '_>))) }
-        }
-    }
-
-    /// Allows access to the current `ImplicitCtxt`.
-    /// Panics if there is no `ImplicitCtxt` available.
-    #[inline]
-    pub fn with_context<F, R>(f: F) -> R
-    where
-        F: for<'a, 'tcx> FnOnce(&ImplicitCtxt<'a, 'tcx>) -> R,
-    {
-        with_context_opt(|opt_context| f(opt_context.expect("no ImplicitCtxt stored in tls")))
-    }
-
-    /// Allows access to the current `ImplicitCtxt` whose tcx field is the same as the tcx argument
-    /// passed in. This means the closure is given an `ImplicitCtxt` with the same `'tcx` lifetime
-    /// as the `TyCtxt` passed in.
-    /// This will panic if you pass it a `TyCtxt` which is different from the current
-    /// `ImplicitCtxt`'s `tcx` field.
-    #[inline]
-    pub fn with_related_context<'tcx, F, R>(tcx: TyCtxt<'tcx>, f: F) -> R
-    where
-        F: FnOnce(&ImplicitCtxt<'_, 'tcx>) -> R,
-    {
-        with_context(|context| unsafe {
-            assert!(ptr_eq(context.tcx.gcx, tcx.gcx));
-            let context: &ImplicitCtxt<'_, '_> = mem::transmute(context);
-            f(context)
-        })
-    }
-
-    /// Allows access to the `TyCtxt` in the current `ImplicitCtxt`.
-    /// Panics if there is no `ImplicitCtxt` available.
-    #[inline]
-    pub fn with<F, R>(f: F) -> R
-    where
-        F: for<'tcx> FnOnce(TyCtxt<'tcx>) -> R,
-    {
-        with_context(|context| f(context.tcx))
-    }
-
-    /// Allows access to the `TyCtxt` in the current `ImplicitCtxt`.
-    /// The closure is passed None if there is no `ImplicitCtxt` available.
-    #[inline]
-    pub fn with_opt<F, R>(f: F) -> R
-    where
-        F: for<'tcx> FnOnce(Option<TyCtxt<'tcx>>) -> R,
-    {
-        with_context_opt(|opt_context| f(opt_context.map(|context| context.tcx)))
-    }
-}
-
 macro_rules! sty_debug_print {
     ($fmt: expr, $ctxt: expr, $($variant: ident),*) => {{
         // Curious inner module to allow variant names to be used as
@@ -2392,12 +2246,6 @@ pub struct DeducedParamAttrs {
     pub read_only: bool,
 }
 
-// We are comparing types with different invariant lifetimes, so `ptr::eq`
-// won't work for us.
-fn ptr_eq<T, U>(t: *const T, u: *const U) -> bool {
-    t as *const () == u as *const ()
-}
-
 pub fn provide(providers: &mut ty::query::Providers) {
     providers.module_reexports =
         |tcx, id| tcx.resolutions(()).reexport_map.get(&id).map(|v| &v[..]);
diff --git a/compiler/rustc_middle/src/ty/context/tls.rs b/compiler/rustc_middle/src/ty/context/tls.rs
new file mode 100644 (file)
index 0000000..71b025d
--- /dev/null
@@ -0,0 +1,187 @@
+use super::{GlobalCtxt, TyCtxt};
+
+use crate::dep_graph::TaskDepsRef;
+use crate::ty::query;
+use rustc_data_structures::sync::{self, Lock};
+use rustc_errors::Diagnostic;
+use std::mem;
+use std::ptr;
+use thin_vec::ThinVec;
+
+/// This is the implicit state of rustc. It contains the current
+/// `TyCtxt` and query. It is updated when creating a local interner or
+/// executing a new query. Whenever there's a `TyCtxt` value available
+/// you should also have access to an `ImplicitCtxt` through the functions
+/// in this module.
+#[derive(Clone)]
+pub struct ImplicitCtxt<'a, 'tcx> {
+    /// The current `TyCtxt`.
+    pub tcx: TyCtxt<'tcx>,
+
+    /// The current query job, if any. This is updated by `JobOwner::start` in
+    /// `ty::query::plumbing` when executing a query.
+    pub query: Option<query::QueryJobId>,
+
+    /// Where to store diagnostics for the current query job, if any.
+    /// This is updated by `JobOwner::start` in `ty::query::plumbing` when executing a query.
+    pub diagnostics: Option<&'a Lock<ThinVec<Diagnostic>>>,
+
+    /// Used to prevent queries from calling too deeply.
+    pub query_depth: usize,
+
+    /// The current dep graph task. This is used to add dependencies to queries
+    /// when executing them.
+    pub task_deps: TaskDepsRef<'a>,
+}
+
+impl<'a, 'tcx> ImplicitCtxt<'a, 'tcx> {
+    pub fn new(gcx: &'tcx GlobalCtxt<'tcx>) -> Self {
+        let tcx = TyCtxt { gcx };
+        ImplicitCtxt {
+            tcx,
+            query: None,
+            diagnostics: None,
+            query_depth: 0,
+            task_deps: TaskDepsRef::Ignore,
+        }
+    }
+}
+
+#[cfg(parallel_compiler)]
+mod tlv {
+    use rustc_rayon_core as rayon_core;
+    use std::ptr;
+
+    /// Gets Rayon's thread-local variable, which is preserved for Rayon jobs.
+    /// This is used to get the pointer to the current `ImplicitCtxt`.
+    #[inline]
+    pub(super) fn get_tlv() -> *const () {
+        ptr::from_exposed_addr(rayon_core::tlv::get())
+    }
+
+    /// Sets Rayon's thread-local variable, which is preserved for Rayon jobs
+    /// to `value` during the call to `f`. It is restored to its previous value after.
+    /// This is used to set the pointer to the new `ImplicitCtxt`.
+    #[inline]
+    pub(super) fn with_tlv<F: FnOnce() -> R, R>(value: *const (), f: F) -> R {
+        rayon_core::tlv::with(value.expose_addr(), f)
+    }
+}
+
+#[cfg(not(parallel_compiler))]
+mod tlv {
+    use std::cell::Cell;
+    use std::ptr;
+
+    thread_local! {
+        /// A thread local variable that stores a pointer to the current `ImplicitCtxt`.
+        static TLV: Cell<*const ()> = const { Cell::new(ptr::null()) };
+    }
+
+    /// Gets the pointer to the current `ImplicitCtxt`.
+    #[inline]
+    pub(super) fn get_tlv() -> *const () {
+        TLV.with(|tlv| tlv.get())
+    }
+
+    /// Sets TLV to `value` during the call to `f`.
+    /// It is restored to its previous value after.
+    /// This is used to set the pointer to the new `ImplicitCtxt`.
+    #[inline]
+    pub(super) fn with_tlv<F: FnOnce() -> R, R>(value: *const (), f: F) -> R {
+        let old = get_tlv();
+        let _reset = rustc_data_structures::OnDrop(move || TLV.with(|tlv| tlv.set(old)));
+        TLV.with(|tlv| tlv.set(value));
+        f()
+    }
+}
+
+#[inline]
+fn erase(context: &ImplicitCtxt<'_, '_>) -> *const () {
+    context as *const _ as *const ()
+}
+
+#[inline]
+unsafe fn downcast<'a, 'tcx>(context: *const ()) -> &'a ImplicitCtxt<'a, 'tcx> {
+    &*(context as *const ImplicitCtxt<'a, 'tcx>)
+}
+
+/// Sets `context` as the new current `ImplicitCtxt` for the duration of the function `f`.
+#[inline]
+pub fn enter_context<'a, 'tcx, F, R>(context: &ImplicitCtxt<'a, 'tcx>, f: F) -> R
+where
+    F: FnOnce(&ImplicitCtxt<'a, 'tcx>) -> R,
+{
+    tlv::with_tlv(erase(context), || f(&context))
+}
+
+/// Allows access to the current `ImplicitCtxt` in a closure if one is available.
+#[inline]
+pub fn with_context_opt<F, R>(f: F) -> R
+where
+    F: for<'a, 'tcx> FnOnce(Option<&ImplicitCtxt<'a, 'tcx>>) -> R,
+{
+    let context = tlv::get_tlv();
+    if context.is_null() {
+        f(None)
+    } else {
+        // We could get an `ImplicitCtxt` pointer from another thread.
+        // Ensure that `ImplicitCtxt` is `Sync`.
+        sync::assert_sync::<ImplicitCtxt<'_, '_>>();
+
+        unsafe { f(Some(downcast(context))) }
+    }
+}
+
+/// Allows access to the current `ImplicitCtxt`.
+/// Panics if there is no `ImplicitCtxt` available.
+#[inline]
+pub fn with_context<F, R>(f: F) -> R
+where
+    F: for<'a, 'tcx> FnOnce(&ImplicitCtxt<'a, 'tcx>) -> R,
+{
+    with_context_opt(|opt_context| f(opt_context.expect("no ImplicitCtxt stored in tls")))
+}
+
+/// Allows access to the current `ImplicitCtxt` whose tcx field is the same as the tcx argument
+/// passed in. This means the closure is given an `ImplicitCtxt` with the same `'tcx` lifetime
+/// as the `TyCtxt` passed in.
+/// This will panic if you pass it a `TyCtxt` which is different from the current
+/// `ImplicitCtxt`'s `tcx` field.
+#[inline]
+pub fn with_related_context<'tcx, F, R>(tcx: TyCtxt<'tcx>, f: F) -> R
+where
+    F: FnOnce(&ImplicitCtxt<'_, 'tcx>) -> R,
+{
+    with_context(|context| {
+        // The two gcx have different invariant lifetimes, so we need to erase them for the comparison.
+        assert!(ptr::eq(
+            context.tcx.gcx as *const _ as *const (),
+            tcx.gcx as *const _ as *const ()
+        ));
+
+        let context: &ImplicitCtxt<'_, '_> = unsafe { mem::transmute(context) };
+
+        f(context)
+    })
+}
+
+/// Allows access to the `TyCtxt` in the current `ImplicitCtxt`.
+/// Panics if there is no `ImplicitCtxt` available.
+#[inline]
+pub fn with<F, R>(f: F) -> R
+where
+    F: for<'tcx> FnOnce(TyCtxt<'tcx>) -> R,
+{
+    with_context(|context| f(context.tcx))
+}
+
+/// Allows access to the `TyCtxt` in the current `ImplicitCtxt`.
+/// The closure is passed None if there is no `ImplicitCtxt` available.
+#[inline]
+pub fn with_opt<F, R>(f: F) -> R
+where
+    F: for<'tcx> FnOnce(Option<TyCtxt<'tcx>>) -> R,
+{
+    with_context_opt(|opt_context| f(opt_context.map(|context| context.tcx)))
+}
index 5d394f71f0d764024b33c0f2e4f047a61a8743e9..c8a700c4e280d6eccd2d19ba8face8a430a6d31f 100644 (file)
@@ -1,24 +1,18 @@
-use crate::traits::{ObligationCause, ObligationCauseCode};
-use crate::ty::diagnostics::suggest_constraining_type_param;
-use crate::ty::print::{with_forced_trimmed_paths, FmtPrinter, Printer};
+use crate::ty::print::{with_forced_trimmed_paths, FmtPrinter, PrettyPrinter};
 use crate::ty::{self, BoundRegionKind, Region, Ty, TyCtxt};
-use rustc_errors::Applicability::{MachineApplicable, MaybeIncorrect};
-use rustc_errors::{pluralize, Diagnostic, MultiSpan};
+use rustc_errors::pluralize;
 use rustc_hir as hir;
 use rustc_hir::def::{CtorOf, DefKind};
 use rustc_hir::def_id::DefId;
-use rustc_span::symbol::{sym, Symbol};
-use rustc_span::{BytePos, Span};
+use rustc_span::symbol::Symbol;
 use rustc_target::spec::abi;
-
 use std::borrow::Cow;
 use std::collections::hash_map::DefaultHasher;
 use std::fmt;
-use std::hash::{Hash, Hasher};
+use std::hash::Hash;
+use std::hash::Hasher;
 use std::path::PathBuf;
 
-use super::print::PrettyPrinter;
-
 #[derive(Clone, Copy, Debug, PartialEq, Eq, TypeFoldable, TypeVisitable, Lift)]
 pub struct ExpectedFound<T> {
     pub expected: T,
@@ -391,620 +385,6 @@ pub fn prefix_string(self, tcx: TyCtxt<'_>) -> Cow<'static, str> {
 }
 
 impl<'tcx> TyCtxt<'tcx> {
-    pub fn note_and_explain_type_err(
-        self,
-        diag: &mut Diagnostic,
-        err: TypeError<'tcx>,
-        cause: &ObligationCause<'tcx>,
-        sp: Span,
-        body_owner_def_id: DefId,
-    ) {
-        use self::TypeError::*;
-        debug!("note_and_explain_type_err err={:?} cause={:?}", err, cause);
-        match err {
-            ArgumentSorts(values, _) | Sorts(values) => {
-                match (values.expected.kind(), values.found.kind()) {
-                    (ty::Closure(..), ty::Closure(..)) => {
-                        diag.note("no two closures, even if identical, have the same type");
-                        diag.help("consider boxing your closure and/or using it as a trait object");
-                    }
-                    (ty::Alias(ty::Opaque, ..), ty::Alias(ty::Opaque, ..)) => {
-                        // Issue #63167
-                        diag.note("distinct uses of `impl Trait` result in different opaque types");
-                    }
-                    (ty::Float(_), ty::Infer(ty::IntVar(_)))
-                        if let Ok(
-                            // Issue #53280
-                            snippet,
-                        ) = self.sess.source_map().span_to_snippet(sp) =>
-                    {
-                        if snippet.chars().all(|c| c.is_digit(10) || c == '-' || c == '_') {
-                            diag.span_suggestion(
-                                sp,
-                                "use a float literal",
-                                format!("{}.0", snippet),
-                                MachineApplicable,
-                            );
-                        }
-                    }
-                    (ty::Param(expected), ty::Param(found)) => {
-                        let generics = self.generics_of(body_owner_def_id);
-                        let e_span = self.def_span(generics.type_param(expected, self).def_id);
-                        if !sp.contains(e_span) {
-                            diag.span_label(e_span, "expected type parameter");
-                        }
-                        let f_span = self.def_span(generics.type_param(found, self).def_id);
-                        if !sp.contains(f_span) {
-                            diag.span_label(f_span, "found type parameter");
-                        }
-                        diag.note(
-                            "a type parameter was expected, but a different one was found; \
-                             you might be missing a type parameter or trait bound",
-                        );
-                        diag.note(
-                            "for more information, visit \
-                             https://doc.rust-lang.org/book/ch10-02-traits.html\
-                             #traits-as-parameters",
-                        );
-                    }
-                    (ty::Alias(ty::Projection, _), ty::Alias(ty::Projection, _)) => {
-                        diag.note("an associated type was expected, but a different one was found");
-                    }
-                    (ty::Param(p), ty::Alias(ty::Projection, proj)) | (ty::Alias(ty::Projection, proj), ty::Param(p))
-                        if self.def_kind(proj.def_id) != DefKind::ImplTraitPlaceholder =>
-                    {
-                        let generics = self.generics_of(body_owner_def_id);
-                        let p_span = self.def_span(generics.type_param(p, self).def_id);
-                        if !sp.contains(p_span) {
-                            diag.span_label(p_span, "this type parameter");
-                        }
-                        let hir = self.hir();
-                        let mut note = true;
-                        if let Some(generics) = generics
-                            .type_param(p, self)
-                            .def_id
-                            .as_local()
-                            .map(|id| hir.local_def_id_to_hir_id(id))
-                            .and_then(|id| self.hir().find_parent(id))
-                            .as_ref()
-                            .and_then(|node| node.generics())
-                        {
-                            // Synthesize the associated type restriction `Add<Output = Expected>`.
-                            // FIXME: extract this logic for use in other diagnostics.
-                            let (trait_ref, assoc_substs) = proj.trait_ref_and_own_substs(self);
-                            let path =
-                                self.def_path_str_with_substs(trait_ref.def_id, trait_ref.substs);
-                            let item_name = self.item_name(proj.def_id);
-                            let item_args = self.format_generic_args(assoc_substs);
-
-                            let path = if path.ends_with('>') {
-                                format!(
-                                    "{}, {}{} = {}>",
-                                    &path[..path.len() - 1],
-                                    item_name,
-                                    item_args,
-                                    p
-                                )
-                            } else {
-                                format!("{}<{}{} = {}>", path, item_name, item_args, p)
-                            };
-                            note = !suggest_constraining_type_param(
-                                self,
-                                generics,
-                                diag,
-                                &format!("{}", proj.self_ty()),
-                                &path,
-                                None,
-                            );
-                        }
-                        if note {
-                            diag.note("you might be missing a type parameter or trait bound");
-                        }
-                    }
-                    (ty::Param(p), ty::Dynamic(..) | ty::Alias(ty::Opaque, ..))
-                    | (ty::Dynamic(..) | ty::Alias(ty::Opaque, ..), ty::Param(p)) => {
-                        let generics = self.generics_of(body_owner_def_id);
-                        let p_span = self.def_span(generics.type_param(p, self).def_id);
-                        if !sp.contains(p_span) {
-                            diag.span_label(p_span, "this type parameter");
-                        }
-                        diag.help("type parameters must be constrained to match other types");
-                        if self.sess.teach(&diag.get_code().unwrap()) {
-                            diag.help(
-                                "given a type parameter `T` and a method `foo`:
-```
-trait Trait<T> { fn foo(&self) -> T; }
-```
-the only ways to implement method `foo` are:
-- constrain `T` with an explicit type:
-```
-impl Trait<String> for X {
-    fn foo(&self) -> String { String::new() }
-}
-```
-- add a trait bound to `T` and call a method on that trait that returns `Self`:
-```
-impl<T: std::default::Default> Trait<T> for X {
-    fn foo(&self) -> T { <T as std::default::Default>::default() }
-}
-```
-- change `foo` to return an argument of type `T`:
-```
-impl<T> Trait<T> for X {
-    fn foo(&self, x: T) -> T { x }
-}
-```",
-                            );
-                        }
-                        diag.note(
-                            "for more information, visit \
-                             https://doc.rust-lang.org/book/ch10-02-traits.html\
-                             #traits-as-parameters",
-                        );
-                    }
-                    (ty::Param(p), ty::Closure(..) | ty::Generator(..)) => {
-                        let generics = self.generics_of(body_owner_def_id);
-                        let p_span = self.def_span(generics.type_param(p, self).def_id);
-                        if !sp.contains(p_span) {
-                            diag.span_label(p_span, "this type parameter");
-                        }
-                        diag.help(&format!(
-                            "every closure has a distinct type and so could not always match the \
-                             caller-chosen type of parameter `{}`",
-                            p
-                        ));
-                    }
-                    (ty::Param(p), _) | (_, ty::Param(p)) => {
-                        let generics = self.generics_of(body_owner_def_id);
-                        let p_span = self.def_span(generics.type_param(p, self).def_id);
-                        if !sp.contains(p_span) {
-                            diag.span_label(p_span, "this type parameter");
-                        }
-                    }
-                    (ty::Alias(ty::Projection, proj_ty), _) if self.def_kind(proj_ty.def_id) != DefKind::ImplTraitPlaceholder => {
-                        self.expected_projection(
-                            diag,
-                            proj_ty,
-                            values,
-                            body_owner_def_id,
-                            cause.code(),
-                        );
-                    }
-                    (_, ty::Alias(ty::Projection, proj_ty)) if self.def_kind(proj_ty.def_id) != DefKind::ImplTraitPlaceholder => {
-                        let msg = format!(
-                            "consider constraining the associated type `{}` to `{}`",
-                            values.found, values.expected,
-                        );
-                        if !(self.suggest_constraining_opaque_associated_type(
-                            diag,
-                            &msg,
-                            proj_ty,
-                            values.expected,
-                        ) || self.suggest_constraint(
-                            diag,
-                            &msg,
-                            body_owner_def_id,
-                            proj_ty,
-                            values.expected,
-                        )) {
-                            diag.help(&msg);
-                            diag.note(
-                                "for more information, visit \
-                                https://doc.rust-lang.org/book/ch19-03-advanced-traits.html",
-                            );
-                        }
-                    }
-                    _ => {}
-                }
-                debug!(
-                    "note_and_explain_type_err expected={:?} ({:?}) found={:?} ({:?})",
-                    values.expected,
-                    values.expected.kind(),
-                    values.found,
-                    values.found.kind(),
-                );
-            }
-            CyclicTy(ty) => {
-                // Watch out for various cases of cyclic types and try to explain.
-                if ty.is_closure() || ty.is_generator() {
-                    diag.note(
-                        "closures cannot capture themselves or take themselves as argument;\n\
-                         this error may be the result of a recent compiler bug-fix,\n\
-                         see issue #46062 <https://github.com/rust-lang/rust/issues/46062>\n\
-                         for more information",
-                    );
-                }
-            }
-            TargetFeatureCast(def_id) => {
-                let target_spans =
-                    self.get_attrs(def_id, sym::target_feature).map(|attr| attr.span);
-                diag.note(
-                    "functions with `#[target_feature]` can only be coerced to `unsafe` function pointers"
-                );
-                diag.span_labels(target_spans, "`#[target_feature]` added here");
-            }
-            _ => {}
-        }
-    }
-
-    fn suggest_constraint(
-        self,
-        diag: &mut Diagnostic,
-        msg: &str,
-        body_owner_def_id: DefId,
-        proj_ty: &ty::AliasTy<'tcx>,
-        ty: Ty<'tcx>,
-    ) -> bool {
-        let assoc = self.associated_item(proj_ty.def_id);
-        let (trait_ref, assoc_substs) = proj_ty.trait_ref_and_own_substs(self);
-        if let Some(item) = self.hir().get_if_local(body_owner_def_id) {
-            if let Some(hir_generics) = item.generics() {
-                // Get the `DefId` for the type parameter corresponding to `A` in `<A as T>::Foo`.
-                // This will also work for `impl Trait`.
-                let def_id = if let ty::Param(param_ty) = proj_ty.self_ty().kind() {
-                    let generics = self.generics_of(body_owner_def_id);
-                    generics.type_param(param_ty, self).def_id
-                } else {
-                    return false;
-                };
-                let Some(def_id) = def_id.as_local() else {
-                    return false;
-                };
-
-                // First look in the `where` clause, as this might be
-                // `fn foo<T>(x: T) where T: Trait`.
-                for pred in hir_generics.bounds_for_param(def_id) {
-                    if self.constrain_generic_bound_associated_type_structured_suggestion(
-                        diag,
-                        &trait_ref,
-                        pred.bounds,
-                        &assoc,
-                        assoc_substs,
-                        ty,
-                        msg,
-                        false,
-                    ) {
-                        return true;
-                    }
-                }
-            }
-        }
-        false
-    }
-
-    /// An associated type was expected and a different type was found.
-    ///
-    /// We perform a few different checks to see what we can suggest:
-    ///
-    ///  - In the current item, look for associated functions that return the expected type and
-    ///    suggest calling them. (Not a structured suggestion.)
-    ///  - If any of the item's generic bounds can be constrained, we suggest constraining the
-    ///    associated type to the found type.
-    ///  - If the associated type has a default type and was expected inside of a `trait`, we
-    ///    mention that this is disallowed.
-    ///  - If all other things fail, and the error is not because of a mismatch between the `trait`
-    ///    and the `impl`, we provide a generic `help` to constrain the assoc type or call an assoc
-    ///    fn that returns the type.
-    fn expected_projection(
-        self,
-        diag: &mut Diagnostic,
-        proj_ty: &ty::AliasTy<'tcx>,
-        values: ExpectedFound<Ty<'tcx>>,
-        body_owner_def_id: DefId,
-        cause_code: &ObligationCauseCode<'_>,
-    ) {
-        let msg = format!(
-            "consider constraining the associated type `{}` to `{}`",
-            values.expected, values.found
-        );
-        let body_owner = self.hir().get_if_local(body_owner_def_id);
-        let current_method_ident = body_owner.and_then(|n| n.ident()).map(|i| i.name);
-
-        // We don't want to suggest calling an assoc fn in a scope where that isn't feasible.
-        let callable_scope = matches!(
-            body_owner,
-            Some(
-                hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(..), .. })
-                    | hir::Node::TraitItem(hir::TraitItem { kind: hir::TraitItemKind::Fn(..), .. })
-                    | hir::Node::ImplItem(hir::ImplItem { kind: hir::ImplItemKind::Fn(..), .. }),
-            )
-        );
-        let impl_comparison =
-            matches!(cause_code, ObligationCauseCode::CompareImplItemObligation { .. });
-        let assoc = self.associated_item(proj_ty.def_id);
-        if !callable_scope || impl_comparison {
-            // We do not want to suggest calling functions when the reason of the
-            // type error is a comparison of an `impl` with its `trait` or when the
-            // scope is outside of a `Body`.
-        } else {
-            // If we find a suitable associated function that returns the expected type, we don't
-            // want the more general suggestion later in this method about "consider constraining
-            // the associated type or calling a method that returns the associated type".
-            let point_at_assoc_fn = self.point_at_methods_that_satisfy_associated_type(
-                diag,
-                assoc.container_id(self),
-                current_method_ident,
-                proj_ty.def_id,
-                values.expected,
-            );
-            // Possibly suggest constraining the associated type to conform to the
-            // found type.
-            if self.suggest_constraint(diag, &msg, body_owner_def_id, proj_ty, values.found)
-                || point_at_assoc_fn
-            {
-                return;
-            }
-        }
-
-        self.suggest_constraining_opaque_associated_type(diag, &msg, proj_ty, values.found);
-
-        if self.point_at_associated_type(diag, body_owner_def_id, values.found) {
-            return;
-        }
-
-        if !impl_comparison {
-            // Generic suggestion when we can't be more specific.
-            if callable_scope {
-                diag.help(&format!(
-                    "{} or calling a method that returns `{}`",
-                    msg, values.expected
-                ));
-            } else {
-                diag.help(&msg);
-            }
-            diag.note(
-                "for more information, visit \
-                 https://doc.rust-lang.org/book/ch19-03-advanced-traits.html",
-            );
-        }
-        if self.sess.teach(&diag.get_code().unwrap()) {
-            diag.help(
-                "given an associated type `T` and a method `foo`:
-```
-trait Trait {
-type T;
-fn foo(&self) -> Self::T;
-}
-```
-the only way of implementing method `foo` is to constrain `T` with an explicit associated type:
-```
-impl Trait for X {
-type T = String;
-fn foo(&self) -> Self::T { String::new() }
-}
-```",
-            );
-        }
-    }
-
-    /// When the expected `impl Trait` is not defined in the current item, it will come from
-    /// a return type. This can occur when dealing with `TryStream` (#71035).
-    fn suggest_constraining_opaque_associated_type(
-        self,
-        diag: &mut Diagnostic,
-        msg: &str,
-        proj_ty: &ty::AliasTy<'tcx>,
-        ty: Ty<'tcx>,
-    ) -> bool {
-        let assoc = self.associated_item(proj_ty.def_id);
-        if let ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }) = *proj_ty.self_ty().kind() {
-            let opaque_local_def_id = def_id.as_local();
-            let opaque_hir_ty = if let Some(opaque_local_def_id) = opaque_local_def_id {
-                match &self.hir().expect_item(opaque_local_def_id).kind {
-                    hir::ItemKind::OpaqueTy(opaque_hir_ty) => opaque_hir_ty,
-                    _ => bug!("The HirId comes from a `ty::Opaque`"),
-                }
-            } else {
-                return false;
-            };
-
-            let (trait_ref, assoc_substs) = proj_ty.trait_ref_and_own_substs(self);
-
-            self.constrain_generic_bound_associated_type_structured_suggestion(
-                diag,
-                &trait_ref,
-                opaque_hir_ty.bounds,
-                assoc,
-                assoc_substs,
-                ty,
-                msg,
-                true,
-            )
-        } else {
-            false
-        }
-    }
-
-    fn point_at_methods_that_satisfy_associated_type(
-        self,
-        diag: &mut Diagnostic,
-        assoc_container_id: DefId,
-        current_method_ident: Option<Symbol>,
-        proj_ty_item_def_id: DefId,
-        expected: Ty<'tcx>,
-    ) -> bool {
-        let items = self.associated_items(assoc_container_id);
-        // Find all the methods in the trait that could be called to construct the
-        // expected associated type.
-        // FIXME: consider suggesting the use of associated `const`s.
-        let methods: Vec<(Span, String)> = items
-            .items
-            .iter()
-            .filter(|(name, item)| {
-                ty::AssocKind::Fn == item.kind && Some(**name) != current_method_ident
-            })
-            .filter_map(|(_, item)| {
-                let method = self.fn_sig(item.def_id);
-                match *method.output().skip_binder().kind() {
-                    ty::Alias(ty::Projection, ty::AliasTy { def_id: item_def_id, .. })
-                        if item_def_id == proj_ty_item_def_id =>
-                    {
-                        Some((
-                            self.def_span(item.def_id),
-                            format!("consider calling `{}`", self.def_path_str(item.def_id)),
-                        ))
-                    }
-                    _ => None,
-                }
-            })
-            .collect();
-        if !methods.is_empty() {
-            // Use a single `help:` to show all the methods in the trait that can
-            // be used to construct the expected associated type.
-            let mut span: MultiSpan =
-                methods.iter().map(|(sp, _)| *sp).collect::<Vec<Span>>().into();
-            let msg = format!(
-                "{some} method{s} {are} available that return{r} `{ty}`",
-                some = if methods.len() == 1 { "a" } else { "some" },
-                s = pluralize!(methods.len()),
-                are = pluralize!("is", methods.len()),
-                r = if methods.len() == 1 { "s" } else { "" },
-                ty = expected
-            );
-            for (sp, label) in methods.into_iter() {
-                span.push_span_label(sp, label);
-            }
-            diag.span_help(span, &msg);
-            return true;
-        }
-        false
-    }
-
-    fn point_at_associated_type(
-        self,
-        diag: &mut Diagnostic,
-        body_owner_def_id: DefId,
-        found: Ty<'tcx>,
-    ) -> bool {
-        let Some(hir_id) = body_owner_def_id.as_local() else {
-            return false;
-        };
-        let hir_id = self.hir().local_def_id_to_hir_id(hir_id);
-        // When `body_owner` is an `impl` or `trait` item, look in its associated types for
-        // `expected` and point at it.
-        let parent_id = self.hir().get_parent_item(hir_id);
-        let item = self.hir().find_by_def_id(parent_id.def_id);
-        debug!("expected_projection parent item {:?}", item);
-        match item {
-            Some(hir::Node::Item(hir::Item { kind: hir::ItemKind::Trait(.., items), .. })) => {
-                // FIXME: account for `#![feature(specialization)]`
-                for item in &items[..] {
-                    match item.kind {
-                        hir::AssocItemKind::Type => {
-                            // FIXME: account for returning some type in a trait fn impl that has
-                            // an assoc type as a return type (#72076).
-                            if let hir::Defaultness::Default { has_value: true } =
-                                self.impl_defaultness(item.id.owner_id)
-                            {
-                                if self.type_of(item.id.owner_id) == found {
-                                    diag.span_label(
-                                        item.span,
-                                        "associated type defaults can't be assumed inside the \
-                                            trait defining them",
-                                    );
-                                    return true;
-                                }
-                            }
-                        }
-                        _ => {}
-                    }
-                }
-            }
-            Some(hir::Node::Item(hir::Item {
-                kind: hir::ItemKind::Impl(hir::Impl { items, .. }),
-                ..
-            })) => {
-                for item in &items[..] {
-                    if let hir::AssocItemKind::Type = item.kind {
-                        if self.type_of(item.id.owner_id) == found {
-                            diag.span_label(item.span, "expected this associated type");
-                            return true;
-                        }
-                    }
-                }
-            }
-            _ => {}
-        }
-        false
-    }
-
-    /// Given a slice of `hir::GenericBound`s, if any of them corresponds to the `trait_ref`
-    /// requirement, provide a structured suggestion to constrain it to a given type `ty`.
-    ///
-    /// `is_bound_surely_present` indicates whether we know the bound we're looking for is
-    /// inside `bounds`. If that's the case then we can consider `bounds` containing only one
-    /// trait bound as the one we're looking for. This can help in cases where the associated
-    /// type is defined on a supertrait of the one present in the bounds.
-    fn constrain_generic_bound_associated_type_structured_suggestion(
-        self,
-        diag: &mut Diagnostic,
-        trait_ref: &ty::TraitRef<'tcx>,
-        bounds: hir::GenericBounds<'_>,
-        assoc: &ty::AssocItem,
-        assoc_substs: &[ty::GenericArg<'tcx>],
-        ty: Ty<'tcx>,
-        msg: &str,
-        is_bound_surely_present: bool,
-    ) -> bool {
-        // FIXME: we would want to call `resolve_vars_if_possible` on `ty` before suggesting.
-
-        let trait_bounds = bounds.iter().filter_map(|bound| match bound {
-            hir::GenericBound::Trait(ptr, hir::TraitBoundModifier::None) => Some(ptr),
-            _ => None,
-        });
-
-        let matching_trait_bounds = trait_bounds
-            .clone()
-            .filter(|ptr| ptr.trait_ref.trait_def_id() == Some(trait_ref.def_id))
-            .collect::<Vec<_>>();
-
-        let span = match &matching_trait_bounds[..] {
-            &[ptr] => ptr.span,
-            &[] if is_bound_surely_present => match &trait_bounds.collect::<Vec<_>>()[..] {
-                &[ptr] => ptr.span,
-                _ => return false,
-            },
-            _ => return false,
-        };
-
-        self.constrain_associated_type_structured_suggestion(
-            diag,
-            span,
-            assoc,
-            assoc_substs,
-            ty,
-            msg,
-        )
-    }
-
-    /// Given a span corresponding to a bound, provide a structured suggestion to set an
-    /// associated type to a given type `ty`.
-    fn constrain_associated_type_structured_suggestion(
-        self,
-        diag: &mut Diagnostic,
-        span: Span,
-        assoc: &ty::AssocItem,
-        assoc_substs: &[ty::GenericArg<'tcx>],
-        ty: Ty<'tcx>,
-        msg: &str,
-    ) -> bool {
-        if let Ok(has_params) =
-            self.sess.source_map().span_to_snippet(span).map(|snippet| snippet.ends_with('>'))
-        {
-            let (span, sugg) = if has_params {
-                let pos = span.hi() - BytePos(1);
-                let span = Span::new(pos, pos, span.ctxt(), span.parent());
-                (span, format!(", {} = {}", assoc.ident(self), ty))
-            } else {
-                let item_args = self.format_generic_args(assoc_substs);
-                (span.shrink_to_hi(), format!("<{}{} = {}>", assoc.ident(self), item_args, ty))
-            };
-            diag.span_suggestion_verbose(span, msg, sugg, MaybeIncorrect);
-            return true;
-        }
-        false
-    }
-
     pub fn short_ty_string(self, ty: Ty<'tcx>) -> (String, Option<PathBuf>) {
         let width = self.sess.diagnostic_width();
         let length_limit = width.saturating_sub(30);
@@ -1047,11 +427,4 @@ pub fn short_ty_string(self, ty: Ty<'tcx>) -> (String, Option<PathBuf>) {
             Err(_) => (regular, None),
         }
     }
-
-    fn format_generic_args(self, args: &[ty::GenericArg<'tcx>]) -> String {
-        FmtPrinter::new(self, hir::def::Namespace::TypeNS)
-            .path_generic_args(Ok, args)
-            .expect("could not write to `String`.")
-            .into_buffer()
-    }
 }
index dfd016569c27a51de3135d2dbcef1706291d9747..66b9d96e69577606abaec0bd90a1c0be9a723761 100644 (file)
@@ -128,7 +128,8 @@ fn to_ty<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> {
             Int(i, signed) => i.to_ty(tcx, signed),
             F32 => tcx.types.f32,
             F64 => tcx.types.f64,
-            Pointer => tcx.mk_mut_ptr(tcx.mk_unit()),
+            // FIXME(erikdesjardins): handle non-default addrspace ptr sizes
+            Pointer(_) => tcx.mk_mut_ptr(tcx.mk_unit()),
         }
     }
 
@@ -138,7 +139,11 @@ fn to_ty<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> {
     fn to_int_ty<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> {
         match *self {
             Int(i, signed) => i.to_ty(tcx, signed),
-            Pointer => tcx.types.usize,
+            // FIXME(erikdesjardins): handle non-default addrspace ptr sizes
+            Pointer(_) => {
+                let signed = false;
+                tcx.data_layout().ptr_sized_integer().to_ty(tcx, signed)
+            }
             F32 | F64 => bug!("floats do not have an int type"),
         }
     }
@@ -812,132 +817,125 @@ fn ty_and_layout_pointee_info_at(
         let tcx = cx.tcx();
         let param_env = cx.param_env();
 
-        let addr_space_of_ty = |ty: Ty<'tcx>| {
-            if ty.is_fn() { cx.data_layout().instruction_address_space } else { AddressSpace::DATA }
-        };
-
-        let pointee_info = match *this.ty.kind() {
-            ty::RawPtr(mt) if offset.bytes() == 0 => {
-                tcx.layout_of(param_env.and(mt.ty)).ok().map(|layout| PointeeInfo {
-                    size: layout.size,
-                    align: layout.align.abi,
-                    safe: None,
-                    address_space: addr_space_of_ty(mt.ty),
-                })
-            }
-            ty::FnPtr(fn_sig) if offset.bytes() == 0 => {
-                tcx.layout_of(param_env.and(tcx.mk_fn_ptr(fn_sig))).ok().map(|layout| PointeeInfo {
-                    size: layout.size,
-                    align: layout.align.abi,
-                    safe: None,
-                    address_space: cx.data_layout().instruction_address_space,
-                })
-            }
-            ty::Ref(_, ty, mt) if offset.bytes() == 0 => {
-                let address_space = addr_space_of_ty(ty);
-                let kind = if tcx.sess.opts.optimize == OptLevel::No {
-                    // Use conservative pointer kind if not optimizing. This saves us the
-                    // Freeze/Unpin queries, and can save time in the codegen backend (noalias
-                    // attributes in LLVM have compile-time cost even in unoptimized builds).
-                    PointerKind::SharedMutable
-                } else {
-                    match mt {
-                        hir::Mutability::Not => {
-                            if ty.is_freeze(tcx, cx.param_env()) {
-                                PointerKind::Frozen
-                            } else {
-                                PointerKind::SharedMutable
+        let pointee_info =
+            match *this.ty.kind() {
+                ty::RawPtr(mt) if offset.bytes() == 0 => {
+                    tcx.layout_of(param_env.and(mt.ty)).ok().map(|layout| PointeeInfo {
+                        size: layout.size,
+                        align: layout.align.abi,
+                        safe: None,
+                    })
+                }
+                ty::FnPtr(fn_sig) if offset.bytes() == 0 => {
+                    tcx.layout_of(param_env.and(tcx.mk_fn_ptr(fn_sig))).ok().map(|layout| {
+                        PointeeInfo { size: layout.size, align: layout.align.abi, safe: None }
+                    })
+                }
+                ty::Ref(_, ty, mt) if offset.bytes() == 0 => {
+                    let kind = if tcx.sess.opts.optimize == OptLevel::No {
+                        // Use conservative pointer kind if not optimizing. This saves us the
+                        // Freeze/Unpin queries, and can save time in the codegen backend (noalias
+                        // attributes in LLVM have compile-time cost even in unoptimized builds).
+                        PointerKind::SharedMutable
+                    } else {
+                        match mt {
+                            hir::Mutability::Not => {
+                                if ty.is_freeze(tcx, cx.param_env()) {
+                                    PointerKind::Frozen
+                                } else {
+                                    PointerKind::SharedMutable
+                                }
                             }
-                        }
-                        hir::Mutability::Mut => {
-                            // References to self-referential structures should not be considered
-                            // noalias, as another pointer to the structure can be obtained, that
-                            // is not based-on the original reference. We consider all !Unpin
-                            // types to be potentially self-referential here.
-                            if ty.is_unpin(tcx, cx.param_env()) {
-                                PointerKind::UniqueBorrowed
-                            } else {
-                                PointerKind::UniqueBorrowedPinned
+                            hir::Mutability::Mut => {
+                                // References to self-referential structures should not be considered
+                                // noalias, as another pointer to the structure can be obtained, that
+                                // is not based-on the original reference. We consider all !Unpin
+                                // types to be potentially self-referential here.
+                                if ty.is_unpin(tcx, cx.param_env()) {
+                                    PointerKind::UniqueBorrowed
+                                } else {
+                                    PointerKind::UniqueBorrowedPinned
+                                }
                             }
                         }
-                    }
-                };
+                    };
 
-                tcx.layout_of(param_env.and(ty)).ok().map(|layout| PointeeInfo {
-                    size: layout.size,
-                    align: layout.align.abi,
-                    safe: Some(kind),
-                    address_space,
-                })
-            }
+                    tcx.layout_of(param_env.and(ty)).ok().map(|layout| PointeeInfo {
+                        size: layout.size,
+                        align: layout.align.abi,
+                        safe: Some(kind),
+                    })
+                }
 
-            _ => {
-                let mut data_variant = match this.variants {
-                    // Within the discriminant field, only the niche itself is
-                    // always initialized, so we only check for a pointer at its
-                    // offset.
-                    //
-                    // If the niche is a pointer, it's either valid (according
-                    // to its type), or null (which the niche field's scalar
-                    // validity range encodes). This allows using
-                    // `dereferenceable_or_null` for e.g., `Option<&T>`, and
-                    // this will continue to work as long as we don't start
-                    // using more niches than just null (e.g., the first page of
-                    // the address space, or unaligned pointers).
-                    Variants::Multiple {
-                        tag_encoding: TagEncoding::Niche { untagged_variant, .. },
-                        tag_field,
-                        ..
-                    } if this.fields.offset(tag_field) == offset => {
-                        Some(this.for_variant(cx, untagged_variant))
-                    }
-                    _ => Some(this),
-                };
+                _ => {
+                    let mut data_variant = match this.variants {
+                        // Within the discriminant field, only the niche itself is
+                        // always initialized, so we only check for a pointer at its
+                        // offset.
+                        //
+                        // If the niche is a pointer, it's either valid (according
+                        // to its type), or null (which the niche field's scalar
+                        // validity range encodes). This allows using
+                        // `dereferenceable_or_null` for e.g., `Option<&T>`, and
+                        // this will continue to work as long as we don't start
+                        // using more niches than just null (e.g., the first page of
+                        // the address space, or unaligned pointers).
+                        Variants::Multiple {
+                            tag_encoding: TagEncoding::Niche { untagged_variant, .. },
+                            tag_field,
+                            ..
+                        } if this.fields.offset(tag_field) == offset => {
+                            Some(this.for_variant(cx, untagged_variant))
+                        }
+                        _ => Some(this),
+                    };
 
-                if let Some(variant) = data_variant {
-                    // We're not interested in any unions.
-                    if let FieldsShape::Union(_) = variant.fields {
-                        data_variant = None;
+                    if let Some(variant) = data_variant {
+                        // We're not interested in any unions.
+                        if let FieldsShape::Union(_) = variant.fields {
+                            data_variant = None;
+                        }
                     }
-                }
 
-                let mut result = None;
-
-                if let Some(variant) = data_variant {
-                    let ptr_end = offset + Pointer.size(cx);
-                    for i in 0..variant.fields.count() {
-                        let field_start = variant.fields.offset(i);
-                        if field_start <= offset {
-                            let field = variant.field(cx, i);
-                            result = field.to_result().ok().and_then(|field| {
-                                if ptr_end <= field_start + field.size {
-                                    // We found the right field, look inside it.
-                                    let field_info =
-                                        field.pointee_info_at(cx, offset - field_start);
-                                    field_info
-                                } else {
-                                    None
+                    let mut result = None;
+
+                    if let Some(variant) = data_variant {
+                        // FIXME(erikdesjardins): handle non-default addrspace ptr sizes
+                        // (requires passing in the expected address space from the caller)
+                        let ptr_end = offset + Pointer(AddressSpace::DATA).size(cx);
+                        for i in 0..variant.fields.count() {
+                            let field_start = variant.fields.offset(i);
+                            if field_start <= offset {
+                                let field = variant.field(cx, i);
+                                result = field.to_result().ok().and_then(|field| {
+                                    if ptr_end <= field_start + field.size {
+                                        // We found the right field, look inside it.
+                                        let field_info =
+                                            field.pointee_info_at(cx, offset - field_start);
+                                        field_info
+                                    } else {
+                                        None
+                                    }
+                                });
+                                if result.is_some() {
+                                    break;
                                 }
-                            });
-                            if result.is_some() {
-                                break;
                             }
                         }
                     }
-                }
 
-                // FIXME(eddyb) This should be for `ptr::Unique<T>`, not `Box<T>`.
-                if let Some(ref mut pointee) = result {
-                    if let ty::Adt(def, _) = this.ty.kind() {
-                        if def.is_box() && offset.bytes() == 0 {
-                            pointee.safe = Some(PointerKind::UniqueOwned);
+                    // FIXME(eddyb) This should be for `ptr::Unique<T>`, not `Box<T>`.
+                    if let Some(ref mut pointee) = result {
+                        if let ty::Adt(def, _) = this.ty.kind() {
+                            if def.is_box() && offset.bytes() == 0 {
+                                pointee.safe = Some(PointerKind::UniqueOwned);
+                            }
                         }
                     }
-                }
 
-                result
-            }
-        };
+                    result
+                }
+            };
 
         debug!(
             "pointee_info_at (offset={:?}, type kind: {:?}) => {:?}",
index f83bceca3b53ba27bdcab4885698a9ea0193c60d..4af29fcbfb58645f30d3d74be4af30a4d3c4a53b 100644 (file)
@@ -2437,6 +2437,7 @@ pub fn adjust_ident(self, mut ident: Ident, scope: DefId) -> Ident {
         ident
     }
 
+    // FIXME(vincenzoapalzzo): move the HirId to a LocalDefId
     pub fn adjust_ident_and_get_scope(
         self,
         mut ident: Ident,
index 9d4ee22a7273beba58c8cb282379a132a7585c03..28b9bdf566018b06c4dab41fdb7b15d601dcb851 100644 (file)
@@ -441,6 +441,10 @@ pub fn def_kind(self, def_id: impl IntoQueryParam<DefId>) -> DefKind {
         self.opt_def_kind(def_id)
             .unwrap_or_else(|| bug!("def_kind: unsupported node: {:?}", def_id))
     }
+
+    pub fn bound_type_of(self, def_id: impl IntoQueryParam<DefId>) -> ty::EarlyBinder<Ty<'tcx>> {
+        ty::EarlyBinder(self.type_of(def_id))
+    }
 }
 
 impl<'tcx> TyCtxtAt<'tcx> {
@@ -449,4 +453,8 @@ pub fn def_kind(self, def_id: impl IntoQueryParam<DefId>) -> DefKind {
         self.opt_def_kind(def_id)
             .unwrap_or_else(|| bug!("def_kind: unsupported node: {:?}", def_id))
     }
+
+    pub fn bound_type_of(self, def_id: impl IntoQueryParam<DefId>) -> ty::EarlyBinder<Ty<'tcx>> {
+        ty::EarlyBinder(self.type_of(def_id))
+    }
 }
index 7d4d35b7fdf940fd23ae8924f2db2e9a9b9a376e..2de886a3e817fd3631520137bec368ee74885b78 100644 (file)
@@ -11,6 +11,7 @@
 use rustc_data_structures::functor::IdFunctor;
 use rustc_hir::def::Namespace;
 use rustc_index::vec::{Idx, IndexVec};
+use rustc_target::abi::TyAndLayout;
 
 use std::fmt;
 use std::mem::ManuallyDrop;
@@ -853,3 +854,9 @@ fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow
         self.substs.visit_with(visitor)
     }
 }
+
+impl<'tcx> TypeVisitable<'tcx> for TyAndLayout<'tcx, Ty<'tcx>> {
+    fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
+        visitor.visit_ty(self.ty)
+    }
+}
index 60076c8cb5f9936d0e16e93798b279fb0d2a0fdc..95abbb50380176be8da44382f48cc725816a1186 100644 (file)
@@ -3,7 +3,6 @@
 use crate::middle::codegen_fn_attrs::CodegenFnAttrFlags;
 use crate::mir;
 use crate::ty::layout::IntegerExt;
-use crate::ty::query::TyCtxtAt;
 use crate::ty::{
     self, DefIdTree, FallibleTypeFolder, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable,
     TypeVisitable,
@@ -637,10 +636,6 @@ pub fn try_expand_impl_trait_type(
         if visitor.found_recursion { Err(expanded_type) } else { Ok(expanded_type) }
     }
 
-    pub fn bound_type_of(self, def_id: DefId) -> ty::EarlyBinder<Ty<'tcx>> {
-        ty::EarlyBinder(self.type_of(def_id))
-    }
-
     pub fn bound_return_position_impl_trait_in_trait_tys(
         self,
         def_id: DefId,
@@ -738,12 +733,6 @@ pub fn generator_layout_and_saved_local_names(
     }
 }
 
-impl<'tcx> TyCtxtAt<'tcx> {
-    pub fn bound_type_of(self, def_id: DefId) -> ty::EarlyBinder<Ty<'tcx>> {
-        ty::EarlyBinder(self.type_of(def_id))
-    }
-}
-
 struct OpaqueTypeExpander<'tcx> {
     // Contains the DefIds of the opaque types that are currently being
     // expanded. When we expand an opaque type we insert the DefId of
index 0bca02589bce131284365337c70dfa61bcae3596..dbba529aef7a5ea6adbf1959bd923111b42db8fd 100644 (file)
@@ -18,6 +18,9 @@ pub fn parse_statement(&self, expr_id: ExprId) -> PResult<StatementKind<'tcx>> {
             @call("mir_storage_dead", args) => {
                 Ok(StatementKind::StorageDead(self.parse_local(args[0])?))
             },
+            @call("mir_deinit", args) => {
+                Ok(StatementKind::Deinit(Box::new(self.parse_place(args[0])?)))
+            },
             @call("mir_retag", args) => {
                 Ok(StatementKind::Retag(RetagKind::Default, Box::new(self.parse_place(args[0])?)))
             },
@@ -141,12 +144,29 @@ fn parse_call(
     fn parse_rvalue(&self, expr_id: ExprId) -> PResult<Rvalue<'tcx>> {
         parse_by_kind!(self, expr_id, _, "rvalue",
             @call("mir_discriminant", args) => self.parse_place(args[0]).map(Rvalue::Discriminant),
+            @call("mir_checked", args) => {
+                parse_by_kind!(self, args[0], _, "binary op",
+                    ExprKind::Binary { op, lhs, rhs } => Ok(Rvalue::CheckedBinaryOp(
+                        *op, Box::new((self.parse_operand(*lhs)?, self.parse_operand(*rhs)?))
+                    )),
+                )
+            },
+            @call("mir_len", args) => Ok(Rvalue::Len(self.parse_place(args[0])?)),
             ExprKind::Borrow { borrow_kind, arg } => Ok(
                 Rvalue::Ref(self.tcx.lifetimes.re_erased, *borrow_kind, self.parse_place(*arg)?)
             ),
             ExprKind::AddressOf { mutability, arg } => Ok(
                 Rvalue::AddressOf(*mutability, self.parse_place(*arg)?)
             ),
+            ExprKind::Binary { op, lhs, rhs } =>  Ok(
+                Rvalue::BinaryOp(*op, Box::new((self.parse_operand(*lhs)?, self.parse_operand(*rhs)?)))
+            ),
+            ExprKind::Unary { op, arg } => Ok(
+                Rvalue::UnaryOp(*op, self.parse_operand(*arg)?)
+            ),
+            ExprKind::Repeat { value, count } => Ok(
+                Rvalue::Repeat(self.parse_operand(*value)?, *count)
+            ),
             _ => self.parse_operand(expr_id).map(Rvalue::Use),
         )
     }
index 7f81aef1c73217d57f5013678b162a4bce27b82f..ced251267d36f9deb95438e76ca848604a6b8b3a 100644 (file)
@@ -600,32 +600,56 @@ pub struct BorrowOfMovedValue<'tcx> {
 pub struct MultipleMutBorrows {
     #[primary_span]
     pub span: Span,
-    #[label]
-    pub binding_span: Span,
     #[subdiagnostic]
-    pub occurences: Vec<MultipleMutBorrowOccurence>,
-    pub name: Ident,
+    pub occurences: Vec<Conflict>,
+}
+
+#[derive(Diagnostic)]
+#[diag(mir_build_already_borrowed)]
+pub struct AlreadyBorrowed {
+    #[primary_span]
+    pub span: Span,
+    #[subdiagnostic]
+    pub occurences: Vec<Conflict>,
+}
+
+#[derive(Diagnostic)]
+#[diag(mir_build_already_mut_borrowed)]
+pub struct AlreadyMutBorrowed {
+    #[primary_span]
+    pub span: Span,
+    #[subdiagnostic]
+    pub occurences: Vec<Conflict>,
+}
+
+#[derive(Diagnostic)]
+#[diag(mir_build_moved_while_borrowed)]
+pub struct MovedWhileBorrowed {
+    #[primary_span]
+    pub span: Span,
+    #[subdiagnostic]
+    pub occurences: Vec<Conflict>,
 }
 
 #[derive(Subdiagnostic)]
-pub enum MultipleMutBorrowOccurence {
-    #[label(mutable_borrow)]
-    Mutable {
+pub enum Conflict {
+    #[label(mir_build_mutable_borrow)]
+    Mut {
         #[primary_span]
         span: Span,
-        name_mut: Ident,
+        name: Ident,
     },
-    #[label(immutable_borrow)]
-    Immutable {
+    #[label(mir_build_borrow)]
+    Ref {
         #[primary_span]
         span: Span,
-        name_immut: Ident,
+        name: Ident,
     },
-    #[label(moved)]
+    #[label(mir_build_moved)]
     Moved {
         #[primary_span]
         span: Span,
-        name_moved: Ident,
+        name: Ident,
     },
 }
 
index 34e637f594842687aaec93b1075bacb16eb8df0b..2640ca56b00e9764bdab912961dfa530798e3aac 100644 (file)
@@ -208,9 +208,9 @@ fn check_match(
             // Don't report arm reachability of desugared `match $iter.into_iter() { iter => .. }`
             // when the iterator is an uninhabited type. unreachable_code will trigger instead.
             hir::MatchSource::ForLoopDesugar if arms.len() == 1 => {}
-            hir::MatchSource::ForLoopDesugar | hir::MatchSource::Normal => {
-                report_arm_reachability(&cx, &report)
-            }
+            hir::MatchSource::ForLoopDesugar
+            | hir::MatchSource::Normal
+            | hir::MatchSource::FormatArgs => report_arm_reachability(&cx, &report),
             // Unreachable patterns in try and await expressions occur when one of
             // the arms are an uninhabited type. Which is OK.
             hir::MatchSource::AwaitDesugar | hir::MatchSource::TryDesugar => {}
@@ -926,58 +926,55 @@ fn check_borrow_conflicts_in_at_patterns(cx: &MatchVisitor<'_, '_, '_>, pat: &Pa
     sub.each_binding(|_, hir_id, span, name| {
         match typeck_results.extract_binding_mode(sess, hir_id, span) {
             Some(ty::BindByReference(mut_inner)) => match (mut_outer, mut_inner) {
-                (Mutability::Not, Mutability::Not) => {} // Both sides are `ref`.
-                (Mutability::Mut, Mutability::Mut) => conflicts_mut_mut.push((span, name)), // 2x `ref mut`.
-                _ => conflicts_mut_ref.push((span, name)), // `ref` + `ref mut` in either direction.
+                // Both sides are `ref`.
+                (Mutability::Not, Mutability::Not) => {}
+                // 2x `ref mut`.
+                (Mutability::Mut, Mutability::Mut) => {
+                    conflicts_mut_mut.push(Conflict::Mut { span, name })
+                }
+                (Mutability::Not, Mutability::Mut) => {
+                    conflicts_mut_ref.push(Conflict::Mut { span, name })
+                }
+                (Mutability::Mut, Mutability::Not) => {
+                    conflicts_mut_ref.push(Conflict::Ref { span, name })
+                }
             },
             Some(ty::BindByValue(_)) if is_binding_by_move(cx, hir_id) => {
-                conflicts_move.push((span, name)) // `ref mut?` + by-move conflict.
+                conflicts_move.push(Conflict::Moved { span, name }) // `ref mut?` + by-move conflict.
             }
             Some(ty::BindByValue(_)) | None => {} // `ref mut?` + by-copy is fine.
         }
     });
 
+    let report_mut_mut = !conflicts_mut_mut.is_empty();
+    let report_mut_ref = !conflicts_mut_ref.is_empty();
+    let report_move_conflict = !conflicts_move.is_empty();
+
+    let mut occurences = match mut_outer {
+        Mutability::Mut => vec![Conflict::Mut { span: binding_span, name }],
+        Mutability::Not => vec![Conflict::Ref { span: binding_span, name }],
+    };
+    occurences.extend(conflicts_mut_mut);
+    occurences.extend(conflicts_mut_ref);
+    occurences.extend(conflicts_move);
+
     // Report errors if any.
-    if !conflicts_mut_mut.is_empty() {
+    if report_mut_mut {
         // Report mutability conflicts for e.g. `ref mut x @ Some(ref mut y)`.
-        let mut occurences = vec![];
-
-        for (span, name_mut) in conflicts_mut_mut {
-            occurences.push(MultipleMutBorrowOccurence::Mutable { span, name_mut });
-        }
-        for (span, name_immut) in conflicts_mut_ref {
-            occurences.push(MultipleMutBorrowOccurence::Immutable { span, name_immut });
-        }
-        for (span, name_moved) in conflicts_move {
-            occurences.push(MultipleMutBorrowOccurence::Moved { span, name_moved });
-        }
-        sess.emit_err(MultipleMutBorrows { span: pat.span, binding_span, occurences, name });
-    } else if !conflicts_mut_ref.is_empty() {
+        sess.emit_err(MultipleMutBorrows { span: pat.span, occurences });
+    } else if report_mut_ref {
         // Report mutability conflicts for e.g. `ref x @ Some(ref mut y)` or the converse.
-        let (primary, also) = match mut_outer {
-            Mutability::Mut => ("mutable", "immutable"),
-            Mutability::Not => ("immutable", "mutable"),
+        match mut_outer {
+            Mutability::Mut => {
+                sess.emit_err(AlreadyMutBorrowed { span: pat.span, occurences });
+            }
+            Mutability::Not => {
+                sess.emit_err(AlreadyBorrowed { span: pat.span, occurences });
+            }
         };
-        let msg =
-            format!("cannot borrow value as {} because it is also borrowed as {}", also, primary);
-        let mut err = sess.struct_span_err(pat.span, &msg);
-        err.span_label(binding_span, format!("{} borrow, by `{}`, occurs here", primary, name));
-        for (span, name) in conflicts_mut_ref {
-            err.span_label(span, format!("{} borrow, by `{}`, occurs here", also, name));
-        }
-        for (span, name) in conflicts_move {
-            err.span_label(span, format!("also moved into `{}` here", name));
-        }
-        err.emit();
-    } else if !conflicts_move.is_empty() {
+    } else if report_move_conflict {
         // Report by-ref and by-move conflicts, e.g. `ref x @ y`.
-        let mut err =
-            sess.struct_span_err(pat.span, "cannot move out of value because it is borrowed");
-        err.span_label(binding_span, format!("value borrowed, by `{}`, here", name));
-        for (span, name) in conflicts_move {
-            err.span_label(span, format!("value moved into `{}` here", name));
-        }
-        err.emit();
+        sess.emit_err(MovedWhileBorrowed { span: pat.span, occurences });
     }
 }
 
index 7f3519945c3fed4ea3ba3ea29da636dd456c5e02..b0d24af958dd7bed2f854c5d41c213412c518af6 100644 (file)
@@ -5,6 +5,7 @@
 use rustc_middle::thir::{FieldPat, Pat, PatKind};
 use rustc_middle::ty::{self, Ty, TyCtxt};
 use rustc_session::lint;
+use rustc_span::def_id::CRATE_DEF_ID;
 use rustc_span::Span;
 use rustc_trait_selection::traits::predicate_for_trait_def;
 use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
@@ -189,10 +190,11 @@ fn type_may_have_partial_eq_impl(&self, ty: Ty<'tcx>) -> bool {
         // using `PartialEq::eq` in this scenario in the past.)
         let partial_eq_trait_id =
             self.tcx().require_lang_item(hir::LangItem::PartialEq, Some(self.span));
+        let def_id = self.tcx().hir().opt_local_def_id(self.id).unwrap_or(CRATE_DEF_ID);
         let obligation: PredicateObligation<'_> = predicate_for_trait_def(
             self.tcx(),
             self.param_env,
-            ObligationCause::misc(self.span, self.id),
+            ObligationCause::misc(self.span, def_id),
             partial_eq_trait_id,
             0,
             [ty, ty],
index 40eefda4f076326002a270044b1526f9988110c3..da101ca7ad279e32a64967ba76fa7ef75c999d2e 100644 (file)
@@ -57,6 +57,15 @@ fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
 }
 
 impl<'tcx> Visitor<'tcx> for ConstGotoOptimizationFinder<'_, 'tcx> {
+    fn visit_basic_block_data(&mut self, block: BasicBlock, data: &BasicBlockData<'tcx>) {
+        if data.is_cleanup {
+            // Because of the restrictions around control flow in cleanup blocks, we don't perform
+            // this optimization at all in such blocks.
+            return;
+        }
+        self.super_basic_block_data(block, data);
+    }
+
     fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location) {
         let _: Option<_> = try {
             let target = terminator.kind.as_goto()?;
index 2f3c65869ef3b2ce275ef446af389d6eeb259e39..e1faa7a08d939425e0de3777b992099c66f9db7a 100644 (file)
@@ -6,7 +6,8 @@
     BinOp, Body, Constant, ConstantKind, LocalDecls, Operand, Place, ProjectionElem, Rvalue,
     SourceInfo, Statement, StatementKind, Terminator, TerminatorKind, UnOp,
 };
-use rustc_middle::ty::{self, TyCtxt};
+use rustc_middle::ty::{self, layout::TyAndLayout, ParamEnv, ParamEnvAnd, SubstsRef, Ty, TyCtxt};
+use rustc_span::symbol::{sym, Symbol};
 
 pub struct InstCombine;
 
@@ -16,7 +17,11 @@ fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
     }
 
     fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
-        let ctx = InstCombineContext { tcx, local_decls: &body.local_decls };
+        let ctx = InstCombineContext {
+            tcx,
+            local_decls: &body.local_decls,
+            param_env: tcx.param_env_reveal_all_normalized(body.source.def_id()),
+        };
         for block in body.basic_blocks.as_mut() {
             for statement in block.statements.iter_mut() {
                 match statement.kind {
@@ -33,6 +38,10 @@ fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
                 &mut block.terminator.as_mut().unwrap(),
                 &mut block.statements,
             );
+            ctx.combine_intrinsic_assert(
+                &mut block.terminator.as_mut().unwrap(),
+                &mut block.statements,
+            );
         }
     }
 }
@@ -40,6 +49,7 @@ fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
 struct InstCombineContext<'tcx, 'a> {
     tcx: TyCtxt<'tcx>,
     local_decls: &'a LocalDecls<'tcx>,
+    param_env: ParamEnv<'tcx>,
 }
 
 impl<'tcx> InstCombineContext<'tcx, '_> {
@@ -200,4 +210,76 @@ fn combine_primitive_clone(
         });
         terminator.kind = TerminatorKind::Goto { target: destination_block };
     }
+
+    fn combine_intrinsic_assert(
+        &self,
+        terminator: &mut Terminator<'tcx>,
+        _statements: &mut Vec<Statement<'tcx>>,
+    ) {
+        let TerminatorKind::Call { func, target, .. } = &mut terminator.kind  else { return; };
+        let Some(target_block) = target else { return; };
+        let func_ty = func.ty(self.local_decls, self.tcx);
+        let Some((intrinsic_name, substs)) = resolve_rust_intrinsic(self.tcx, func_ty) else {
+            return;
+        };
+        // The intrinsics we are interested in have one generic parameter
+        if substs.is_empty() {
+            return;
+        }
+        let ty = substs.type_at(0);
+
+        // Check this is a foldable intrinsic before we query the layout of our generic parameter
+        let Some(assert_panics) = intrinsic_assert_panics(intrinsic_name) else { return; };
+        let Ok(layout) = self.tcx.layout_of(self.param_env.and(ty)) else { return; };
+        if assert_panics(self.tcx, self.param_env.and(layout)) {
+            // If we know the assert panics, indicate to later opts that the call diverges
+            *target = None;
+        } else {
+            // If we know the assert does not panic, turn the call into a Goto
+            terminator.kind = TerminatorKind::Goto { target: *target_block };
+        }
+    }
+}
+
+fn intrinsic_assert_panics<'tcx>(
+    intrinsic_name: Symbol,
+) -> Option<fn(TyCtxt<'tcx>, ParamEnvAnd<'tcx, TyAndLayout<'tcx>>) -> bool> {
+    fn inhabited_predicate<'tcx>(
+        _tcx: TyCtxt<'tcx>,
+        param_env_and_layout: ParamEnvAnd<'tcx, TyAndLayout<'tcx>>,
+    ) -> bool {
+        let (_param_env, layout) = param_env_and_layout.into_parts();
+        layout.abi.is_uninhabited()
+    }
+    fn zero_valid_predicate<'tcx>(
+        tcx: TyCtxt<'tcx>,
+        param_env_and_layout: ParamEnvAnd<'tcx, TyAndLayout<'tcx>>,
+    ) -> bool {
+        !tcx.permits_zero_init(param_env_and_layout)
+    }
+    fn mem_uninitialized_valid_predicate<'tcx>(
+        tcx: TyCtxt<'tcx>,
+        param_env_and_layout: ParamEnvAnd<'tcx, TyAndLayout<'tcx>>,
+    ) -> bool {
+        !tcx.permits_uninit_init(param_env_and_layout)
+    }
+
+    match intrinsic_name {
+        sym::assert_inhabited => Some(inhabited_predicate),
+        sym::assert_zero_valid => Some(zero_valid_predicate),
+        sym::assert_mem_uninitialized_valid => Some(mem_uninitialized_valid_predicate),
+        _ => None,
+    }
+}
+
+fn resolve_rust_intrinsic<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    func_ty: Ty<'tcx>,
+) -> Option<(Symbol, SubstsRef<'tcx>)> {
+    if let ty::FnDef(def_id, substs) = *func_ty.kind() {
+        if tcx.is_intrinsic(def_id) {
+            return Some((tcx.item_name(def_id), substs));
+        }
+    }
+    None
 }
index 20b7fdcfe6d4d44a5b98de025359fb1ed99b2974..4a598862d10f8ad61e218fd28ef28026e48dae00 100644 (file)
@@ -90,7 +90,6 @@
 pub mod simplify;
 mod simplify_branches;
 mod simplify_comparison_integral;
-mod simplify_try;
 mod sroa;
 mod uninhabited_enum_branching;
 mod unreachable_prop;
@@ -567,8 +566,6 @@ fn o1<T>(x: T) -> WithMinOptLevel<T> {
             &o1(simplify_branches::SimplifyConstCondition::new("after-const-prop")),
             &early_otherwise_branch::EarlyOtherwiseBranch,
             &simplify_comparison_integral::SimplifyComparisonIntegral,
-            &simplify_try::SimplifyArmIdentity,
-            &simplify_try::SimplifyBranchSame,
             &dead_store_elimination::DeadStoreElimination,
             &dest_prop::DestinationPropagation,
             &o1(simplify_branches::SimplifyConstCondition::new("final")),
diff --git a/compiler/rustc_mir_transform/src/simplify_try.rs b/compiler/rustc_mir_transform/src/simplify_try.rs
deleted file mode 100644 (file)
index e4f3ace..0000000
+++ /dev/null
@@ -1,822 +0,0 @@
-//! The general point of the optimizations provided here is to simplify something like:
-//!
-//! ```rust
-//! # fn foo<T, E>(x: Result<T, E>) -> Result<T, E> {
-//! match x {
-//!     Ok(x) => Ok(x),
-//!     Err(x) => Err(x)
-//! }
-//! # }
-//! ```
-//!
-//! into just `x`.
-
-use crate::{simplify, MirPass};
-use itertools::Itertools as _;
-use rustc_index::{bit_set::BitSet, vec::IndexVec};
-use rustc_middle::mir::visit::{NonUseContext, PlaceContext, Visitor};
-use rustc_middle::mir::*;
-use rustc_middle::ty::{self, List, Ty, TyCtxt};
-use rustc_target::abi::VariantIdx;
-use std::iter::{once, Enumerate, Peekable};
-use std::slice::Iter;
-
-/// Simplifies arms of form `Variant(x) => Variant(x)` to just a move.
-///
-/// This is done by transforming basic blocks where the statements match:
-///
-/// ```ignore (MIR)
-/// _LOCAL_TMP = ((_LOCAL_1 as Variant ).FIELD: TY );
-/// _TMP_2 = _LOCAL_TMP;
-/// ((_LOCAL_0 as Variant).FIELD: TY) = move _TMP_2;
-/// discriminant(_LOCAL_0) = VAR_IDX;
-/// ```
-///
-/// into:
-///
-/// ```ignore (MIR)
-/// _LOCAL_0 = move _LOCAL_1
-/// ```
-pub struct SimplifyArmIdentity;
-
-#[derive(Debug)]
-struct ArmIdentityInfo<'tcx> {
-    /// Storage location for the variant's field
-    local_temp_0: Local,
-    /// Storage location holding the variant being read from
-    local_1: Local,
-    /// The variant field being read from
-    vf_s0: VarField<'tcx>,
-    /// Index of the statement which loads the variant being read
-    get_variant_field_stmt: usize,
-
-    /// Tracks each assignment to a temporary of the variant's field
-    field_tmp_assignments: Vec<(Local, Local)>,
-
-    /// Storage location holding the variant's field that was read from
-    local_tmp_s1: Local,
-    /// Storage location holding the enum that we are writing to
-    local_0: Local,
-    /// The variant field being written to
-    vf_s1: VarField<'tcx>,
-
-    /// Storage location that the discriminant is being written to
-    set_discr_local: Local,
-    /// The variant being written
-    set_discr_var_idx: VariantIdx,
-
-    /// Index of the statement that should be overwritten as a move
-    stmt_to_overwrite: usize,
-    /// SourceInfo for the new move
-    source_info: SourceInfo,
-
-    /// Indices of matching Storage{Live,Dead} statements encountered.
-    /// (StorageLive index,, StorageDead index, Local)
-    storage_stmts: Vec<(usize, usize, Local)>,
-
-    /// The statements that should be removed (turned into nops)
-    stmts_to_remove: Vec<usize>,
-
-    /// Indices of debug variables that need to be adjusted to point to
-    // `{local_0}.{dbg_projection}`.
-    dbg_info_to_adjust: Vec<usize>,
-
-    /// The projection used to rewrite debug info.
-    dbg_projection: &'tcx List<PlaceElem<'tcx>>,
-}
-
-fn get_arm_identity_info<'a, 'tcx>(
-    stmts: &'a [Statement<'tcx>],
-    locals_count: usize,
-    debug_info: &'a [VarDebugInfo<'tcx>],
-) -> Option<ArmIdentityInfo<'tcx>> {
-    // This can't possibly match unless there are at least 3 statements in the block
-    // so fail fast on tiny blocks.
-    if stmts.len() < 3 {
-        return None;
-    }
-
-    let mut tmp_assigns = Vec::new();
-    let mut nop_stmts = Vec::new();
-    let mut storage_stmts = Vec::new();
-    let mut storage_live_stmts = Vec::new();
-    let mut storage_dead_stmts = Vec::new();
-
-    type StmtIter<'a, 'tcx> = Peekable<Enumerate<Iter<'a, Statement<'tcx>>>>;
-
-    fn is_storage_stmt(stmt: &Statement<'_>) -> bool {
-        matches!(stmt.kind, StatementKind::StorageLive(_) | StatementKind::StorageDead(_))
-    }
-
-    /// Eats consecutive Statements which match `test`, performing the specified `action` for each.
-    /// The iterator `stmt_iter` is not advanced if none were matched.
-    fn try_eat<'a, 'tcx>(
-        stmt_iter: &mut StmtIter<'a, 'tcx>,
-        test: impl Fn(&'a Statement<'tcx>) -> bool,
-        mut action: impl FnMut(usize, &'a Statement<'tcx>),
-    ) {
-        while stmt_iter.peek().map_or(false, |(_, stmt)| test(stmt)) {
-            let (idx, stmt) = stmt_iter.next().unwrap();
-
-            action(idx, stmt);
-        }
-    }
-
-    /// Eats consecutive `StorageLive` and `StorageDead` Statements.
-    /// The iterator `stmt_iter` is not advanced if none were found.
-    fn try_eat_storage_stmts(
-        stmt_iter: &mut StmtIter<'_, '_>,
-        storage_live_stmts: &mut Vec<(usize, Local)>,
-        storage_dead_stmts: &mut Vec<(usize, Local)>,
-    ) {
-        try_eat(stmt_iter, is_storage_stmt, |idx, stmt| {
-            if let StatementKind::StorageLive(l) = stmt.kind {
-                storage_live_stmts.push((idx, l));
-            } else if let StatementKind::StorageDead(l) = stmt.kind {
-                storage_dead_stmts.push((idx, l));
-            }
-        })
-    }
-
-    fn is_tmp_storage_stmt(stmt: &Statement<'_>) -> bool {
-        use rustc_middle::mir::StatementKind::Assign;
-        if let Assign(box (place, Rvalue::Use(Operand::Copy(p) | Operand::Move(p)))) = &stmt.kind {
-            place.as_local().is_some() && p.as_local().is_some()
-        } else {
-            false
-        }
-    }
-
-    /// Eats consecutive `Assign` Statements.
-    // The iterator `stmt_iter` is not advanced if none were found.
-    fn try_eat_assign_tmp_stmts(
-        stmt_iter: &mut StmtIter<'_, '_>,
-        tmp_assigns: &mut Vec<(Local, Local)>,
-        nop_stmts: &mut Vec<usize>,
-    ) {
-        try_eat(stmt_iter, is_tmp_storage_stmt, |idx, stmt| {
-            use rustc_middle::mir::StatementKind::Assign;
-            if let Assign(box (place, Rvalue::Use(Operand::Copy(p) | Operand::Move(p)))) =
-                &stmt.kind
-            {
-                tmp_assigns.push((place.as_local().unwrap(), p.as_local().unwrap()));
-                nop_stmts.push(idx);
-            }
-        })
-    }
-
-    fn find_storage_live_dead_stmts_for_local(
-        local: Local,
-        stmts: &[Statement<'_>],
-    ) -> Option<(usize, usize)> {
-        trace!("looking for {:?}", local);
-        let mut storage_live_stmt = None;
-        let mut storage_dead_stmt = None;
-        for (idx, stmt) in stmts.iter().enumerate() {
-            if stmt.kind == StatementKind::StorageLive(local) {
-                storage_live_stmt = Some(idx);
-            } else if stmt.kind == StatementKind::StorageDead(local) {
-                storage_dead_stmt = Some(idx);
-            }
-        }
-
-        Some((storage_live_stmt?, storage_dead_stmt.unwrap_or(usize::MAX)))
-    }
-
-    // Try to match the expected MIR structure with the basic block we're processing.
-    // We want to see something that looks like:
-    // ```
-    // (StorageLive(_) | StorageDead(_));*
-    // _LOCAL_INTO = ((_LOCAL_FROM as Variant).FIELD: TY);
-    // (StorageLive(_) | StorageDead(_));*
-    // (tmp_n+1 = tmp_n);*
-    // (StorageLive(_) | StorageDead(_));*
-    // (tmp_n+1 = tmp_n);*
-    // ((LOCAL_FROM as Variant).FIELD: TY) = move tmp;
-    // discriminant(LOCAL_FROM) = VariantIdx;
-    // (StorageLive(_) | StorageDead(_));*
-    // ```
-    let mut stmt_iter = stmts.iter().enumerate().peekable();
-
-    try_eat_storage_stmts(&mut stmt_iter, &mut storage_live_stmts, &mut storage_dead_stmts);
-
-    let (get_variant_field_stmt, stmt) = stmt_iter.next()?;
-    let (local_tmp_s0, local_1, vf_s0, dbg_projection) = match_get_variant_field(stmt)?;
-
-    try_eat_storage_stmts(&mut stmt_iter, &mut storage_live_stmts, &mut storage_dead_stmts);
-
-    try_eat_assign_tmp_stmts(&mut stmt_iter, &mut tmp_assigns, &mut nop_stmts);
-
-    try_eat_storage_stmts(&mut stmt_iter, &mut storage_live_stmts, &mut storage_dead_stmts);
-
-    try_eat_assign_tmp_stmts(&mut stmt_iter, &mut tmp_assigns, &mut nop_stmts);
-
-    let (idx, stmt) = stmt_iter.next()?;
-    let (local_tmp_s1, local_0, vf_s1) = match_set_variant_field(stmt)?;
-    nop_stmts.push(idx);
-
-    let (idx, stmt) = stmt_iter.next()?;
-    let (set_discr_local, set_discr_var_idx) = match_set_discr(stmt)?;
-    let discr_stmt_source_info = stmt.source_info;
-    nop_stmts.push(idx);
-
-    try_eat_storage_stmts(&mut stmt_iter, &mut storage_live_stmts, &mut storage_dead_stmts);
-
-    for (live_idx, live_local) in storage_live_stmts {
-        if let Some(i) = storage_dead_stmts.iter().rposition(|(_, l)| *l == live_local) {
-            let (dead_idx, _) = storage_dead_stmts.swap_remove(i);
-            storage_stmts.push((live_idx, dead_idx, live_local));
-
-            if live_local == local_tmp_s0 {
-                nop_stmts.push(get_variant_field_stmt);
-            }
-        }
-    }
-    // We sort primitive usize here so we can use unstable sort
-    nop_stmts.sort_unstable();
-
-    // Use one of the statements we're going to discard between the point
-    // where the storage location for the variant field becomes live and
-    // is killed.
-    let (live_idx, dead_idx) = find_storage_live_dead_stmts_for_local(local_tmp_s0, stmts)?;
-    let stmt_to_overwrite =
-        nop_stmts.iter().find(|stmt_idx| live_idx < **stmt_idx && **stmt_idx < dead_idx);
-
-    let mut tmp_assigned_vars = BitSet::new_empty(locals_count);
-    for (l, r) in &tmp_assigns {
-        tmp_assigned_vars.insert(*l);
-        tmp_assigned_vars.insert(*r);
-    }
-
-    let dbg_info_to_adjust: Vec<_> = debug_info
-        .iter()
-        .enumerate()
-        .filter_map(|(i, var_info)| {
-            if let VarDebugInfoContents::Place(p) = var_info.value {
-                if tmp_assigned_vars.contains(p.local) {
-                    return Some(i);
-                }
-            }
-
-            None
-        })
-        .collect();
-
-    Some(ArmIdentityInfo {
-        local_temp_0: local_tmp_s0,
-        local_1,
-        vf_s0,
-        get_variant_field_stmt,
-        field_tmp_assignments: tmp_assigns,
-        local_tmp_s1,
-        local_0,
-        vf_s1,
-        set_discr_local,
-        set_discr_var_idx,
-        stmt_to_overwrite: *stmt_to_overwrite?,
-        source_info: discr_stmt_source_info,
-        storage_stmts,
-        stmts_to_remove: nop_stmts,
-        dbg_info_to_adjust,
-        dbg_projection,
-    })
-}
-
-fn optimization_applies<'tcx>(
-    opt_info: &ArmIdentityInfo<'tcx>,
-    local_decls: &IndexVec<Local, LocalDecl<'tcx>>,
-    local_uses: &IndexVec<Local, usize>,
-    var_debug_info: &[VarDebugInfo<'tcx>],
-) -> bool {
-    trace!("testing if optimization applies...");
-
-    // FIXME(wesleywiser): possibly relax this restriction?
-    if opt_info.local_0 == opt_info.local_1 {
-        trace!("NO: moving into ourselves");
-        return false;
-    } else if opt_info.vf_s0 != opt_info.vf_s1 {
-        trace!("NO: the field-and-variant information do not match");
-        return false;
-    } else if local_decls[opt_info.local_0].ty != local_decls[opt_info.local_1].ty {
-        // FIXME(Centril,oli-obk): possibly relax to same layout?
-        trace!("NO: source and target locals have different types");
-        return false;
-    } else if (opt_info.local_0, opt_info.vf_s0.var_idx)
-        != (opt_info.set_discr_local, opt_info.set_discr_var_idx)
-    {
-        trace!("NO: the discriminants do not match");
-        return false;
-    }
-
-    // Verify the assignment chain consists of the form b = a; c = b; d = c; etc...
-    if opt_info.field_tmp_assignments.is_empty() {
-        trace!("NO: no assignments found");
-        return false;
-    }
-    let mut last_assigned_to = opt_info.field_tmp_assignments[0].1;
-    let source_local = last_assigned_to;
-    for (l, r) in &opt_info.field_tmp_assignments {
-        if *r != last_assigned_to {
-            trace!("NO: found unexpected assignment {:?} = {:?}", l, r);
-            return false;
-        }
-
-        last_assigned_to = *l;
-    }
-
-    // Check that the first and last used locals are only used twice
-    // since they are of the form:
-    //
-    // ```
-    // _first = ((_x as Variant).n: ty);
-    // _n = _first;
-    // ...
-    // ((_y as Variant).n: ty) = _n;
-    // discriminant(_y) = z;
-    // ```
-    for (l, r) in &opt_info.field_tmp_assignments {
-        if local_uses[*l] != 2 {
-            warn!("NO: FAILED assignment chain local {:?} was used more than twice", l);
-            return false;
-        } else if local_uses[*r] != 2 {
-            warn!("NO: FAILED assignment chain local {:?} was used more than twice", r);
-            return false;
-        }
-    }
-
-    // Check that debug info only points to full Locals and not projections.
-    for dbg_idx in &opt_info.dbg_info_to_adjust {
-        let dbg_info = &var_debug_info[*dbg_idx];
-        if let VarDebugInfoContents::Place(p) = dbg_info.value {
-            if !p.projection.is_empty() {
-                trace!("NO: debug info for {:?} had a projection {:?}", dbg_info.name, p);
-                return false;
-            }
-        }
-    }
-
-    if source_local != opt_info.local_temp_0 {
-        trace!(
-            "NO: start of assignment chain does not match enum variant temp: {:?} != {:?}",
-            source_local,
-            opt_info.local_temp_0
-        );
-        return false;
-    } else if last_assigned_to != opt_info.local_tmp_s1 {
-        trace!(
-            "NO: end of assignment chain does not match written enum temp: {:?} != {:?}",
-            last_assigned_to,
-            opt_info.local_tmp_s1
-        );
-        return false;
-    }
-
-    trace!("SUCCESS: optimization applies!");
-    true
-}
-
-impl<'tcx> MirPass<'tcx> for SimplifyArmIdentity {
-    fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
-        // FIXME(77359): This optimization can result in unsoundness.
-        if !tcx.sess.opts.unstable_opts.unsound_mir_opts {
-            return;
-        }
-
-        let source = body.source;
-        trace!("running SimplifyArmIdentity on {:?}", source);
-
-        let local_uses = LocalUseCounter::get_local_uses(body);
-        for bb in body.basic_blocks.as_mut() {
-            if let Some(opt_info) =
-                get_arm_identity_info(&bb.statements, body.local_decls.len(), &body.var_debug_info)
-            {
-                trace!("got opt_info = {:#?}", opt_info);
-                if !optimization_applies(
-                    &opt_info,
-                    &body.local_decls,
-                    &local_uses,
-                    &body.var_debug_info,
-                ) {
-                    debug!("optimization skipped for {:?}", source);
-                    continue;
-                }
-
-                // Also remove unused Storage{Live,Dead} statements which correspond
-                // to temps used previously.
-                for (live_idx, dead_idx, local) in &opt_info.storage_stmts {
-                    // The temporary that we've read the variant field into is scoped to this block,
-                    // so we can remove the assignment.
-                    if *local == opt_info.local_temp_0 {
-                        bb.statements[opt_info.get_variant_field_stmt].make_nop();
-                    }
-
-                    for (left, right) in &opt_info.field_tmp_assignments {
-                        if local == left || local == right {
-                            bb.statements[*live_idx].make_nop();
-                            bb.statements[*dead_idx].make_nop();
-                        }
-                    }
-                }
-
-                // Right shape; transform
-                for stmt_idx in opt_info.stmts_to_remove {
-                    bb.statements[stmt_idx].make_nop();
-                }
-
-                let stmt = &mut bb.statements[opt_info.stmt_to_overwrite];
-                stmt.source_info = opt_info.source_info;
-                stmt.kind = StatementKind::Assign(Box::new((
-                    opt_info.local_0.into(),
-                    Rvalue::Use(Operand::Move(opt_info.local_1.into())),
-                )));
-
-                bb.statements.retain(|stmt| stmt.kind != StatementKind::Nop);
-
-                // Fix the debug info to point to the right local
-                for dbg_index in opt_info.dbg_info_to_adjust {
-                    let dbg_info = &mut body.var_debug_info[dbg_index];
-                    assert!(
-                        matches!(dbg_info.value, VarDebugInfoContents::Place(_)),
-                        "value was not a Place"
-                    );
-                    if let VarDebugInfoContents::Place(p) = &mut dbg_info.value {
-                        assert!(p.projection.is_empty());
-                        p.local = opt_info.local_0;
-                        p.projection = opt_info.dbg_projection;
-                    }
-                }
-
-                trace!("block is now {:?}", bb.statements);
-            }
-        }
-    }
-}
-
-struct LocalUseCounter {
-    local_uses: IndexVec<Local, usize>,
-}
-
-impl LocalUseCounter {
-    fn get_local_uses(body: &Body<'_>) -> IndexVec<Local, usize> {
-        let mut counter = LocalUseCounter { local_uses: IndexVec::from_elem(0, &body.local_decls) };
-        counter.visit_body(body);
-        counter.local_uses
-    }
-}
-
-impl Visitor<'_> for LocalUseCounter {
-    fn visit_local(&mut self, local: Local, context: PlaceContext, _location: Location) {
-        if context.is_storage_marker()
-            || context == PlaceContext::NonUse(NonUseContext::VarDebugInfo)
-        {
-            return;
-        }
-
-        self.local_uses[local] += 1;
-    }
-}
-
-/// Match on:
-/// ```ignore (MIR)
-/// _LOCAL_INTO = ((_LOCAL_FROM as Variant).FIELD: TY);
-/// ```
-fn match_get_variant_field<'tcx>(
-    stmt: &Statement<'tcx>,
-) -> Option<(Local, Local, VarField<'tcx>, &'tcx List<PlaceElem<'tcx>>)> {
-    match &stmt.kind {
-        StatementKind::Assign(box (
-            place_into,
-            Rvalue::Use(Operand::Copy(pf) | Operand::Move(pf)),
-        )) => {
-            let local_into = place_into.as_local()?;
-            let (local_from, vf) = match_variant_field_place(*pf)?;
-            Some((local_into, local_from, vf, pf.projection))
-        }
-        _ => None,
-    }
-}
-
-/// Match on:
-/// ```ignore (MIR)
-/// ((_LOCAL_FROM as Variant).FIELD: TY) = move _LOCAL_INTO;
-/// ```
-fn match_set_variant_field<'tcx>(stmt: &Statement<'tcx>) -> Option<(Local, Local, VarField<'tcx>)> {
-    match &stmt.kind {
-        StatementKind::Assign(box (place_from, Rvalue::Use(Operand::Move(place_into)))) => {
-            let local_into = place_into.as_local()?;
-            let (local_from, vf) = match_variant_field_place(*place_from)?;
-            Some((local_into, local_from, vf))
-        }
-        _ => None,
-    }
-}
-
-/// Match on:
-/// ```ignore (MIR)
-/// discriminant(_LOCAL_TO_SET) = VAR_IDX;
-/// ```
-fn match_set_discr(stmt: &Statement<'_>) -> Option<(Local, VariantIdx)> {
-    match &stmt.kind {
-        StatementKind::SetDiscriminant { place, variant_index } => {
-            Some((place.as_local()?, *variant_index))
-        }
-        _ => None,
-    }
-}
-
-#[derive(PartialEq, Debug)]
-struct VarField<'tcx> {
-    field: Field,
-    field_ty: Ty<'tcx>,
-    var_idx: VariantIdx,
-}
-
-/// Match on `((_LOCAL as Variant).FIELD: TY)`.
-fn match_variant_field_place(place: Place<'_>) -> Option<(Local, VarField<'_>)> {
-    match place.as_ref() {
-        PlaceRef {
-            local,
-            projection: &[ProjectionElem::Downcast(_, var_idx), ProjectionElem::Field(field, ty)],
-        } => Some((local, VarField { field, field_ty: ty, var_idx })),
-        _ => None,
-    }
-}
-
-/// Simplifies `SwitchInt(_) -> [targets]`,
-/// where all the `targets` have the same form,
-/// into `goto -> target_first`.
-pub struct SimplifyBranchSame;
-
-impl<'tcx> MirPass<'tcx> for SimplifyBranchSame {
-    fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
-        // This optimization is disabled by default for now due to
-        // soundness concerns; see issue #89485 and PR #89489.
-        if !tcx.sess.opts.unstable_opts.unsound_mir_opts {
-            return;
-        }
-
-        trace!("Running SimplifyBranchSame on {:?}", body.source);
-        let finder = SimplifyBranchSameOptimizationFinder { body, tcx };
-        let opts = finder.find();
-
-        let did_remove_blocks = opts.len() > 0;
-        for opt in opts.iter() {
-            trace!("SUCCESS: Applying optimization {:?}", opt);
-            // Replace `SwitchInt(..) -> [bb_first, ..];` with a `goto -> bb_first;`.
-            body.basic_blocks_mut()[opt.bb_to_opt_terminator].terminator_mut().kind =
-                TerminatorKind::Goto { target: opt.bb_to_goto };
-        }
-
-        if did_remove_blocks {
-            // We have dead blocks now, so remove those.
-            simplify::remove_dead_blocks(tcx, body);
-        }
-    }
-}
-
-#[derive(Debug)]
-struct SimplifyBranchSameOptimization {
-    /// All basic blocks are equal so go to this one
-    bb_to_goto: BasicBlock,
-    /// Basic block where the terminator can be simplified to a goto
-    bb_to_opt_terminator: BasicBlock,
-}
-
-struct SwitchTargetAndValue {
-    target: BasicBlock,
-    // None in case of the `otherwise` case
-    value: Option<u128>,
-}
-
-struct SimplifyBranchSameOptimizationFinder<'a, 'tcx> {
-    body: &'a Body<'tcx>,
-    tcx: TyCtxt<'tcx>,
-}
-
-impl<'tcx> SimplifyBranchSameOptimizationFinder<'_, 'tcx> {
-    fn find(&self) -> Vec<SimplifyBranchSameOptimization> {
-        self.body
-            .basic_blocks
-            .iter_enumerated()
-            .filter_map(|(bb_idx, bb)| {
-                let (discr_switched_on, targets_and_values) = match &bb.terminator().kind {
-                    TerminatorKind::SwitchInt { targets, discr, .. } => {
-                        let targets_and_values: Vec<_> = targets.iter()
-                            .map(|(val, target)| SwitchTargetAndValue { target, value: Some(val) })
-                            .chain(once(SwitchTargetAndValue { target: targets.otherwise(), value: None }))
-                            .collect();
-                        (discr, targets_and_values)
-                    },
-                    _ => return None,
-                };
-
-                // find the adt that has its discriminant read
-                // assuming this must be the last statement of the block
-                let adt_matched_on = match &bb.statements.last()?.kind {
-                    StatementKind::Assign(box (place, rhs))
-                        if Some(*place) == discr_switched_on.place() =>
-                    {
-                        match rhs {
-                            Rvalue::Discriminant(adt_place) if adt_place.ty(self.body, self.tcx).ty.is_enum() => adt_place,
-                            _ => {
-                                trace!("NO: expected a discriminant read of an enum instead of: {:?}", rhs);
-                                return None;
-                            }
-                        }
-                    }
-                    other => {
-                        trace!("NO: expected an assignment of a discriminant read to a place. Found: {:?}", other);
-                        return None
-                    },
-                };
-
-                let mut iter_bbs_reachable = targets_and_values
-                    .iter()
-                    .map(|target_and_value| (target_and_value, &self.body.basic_blocks[target_and_value.target]))
-                    .filter(|(_, bb)| {
-                        // Reaching `unreachable` is UB so assume it doesn't happen.
-                        bb.terminator().kind != TerminatorKind::Unreachable
-                    })
-                    .peekable();
-
-                let bb_first = iter_bbs_reachable.peek().map_or(&targets_and_values[0], |(idx, _)| *idx);
-                let mut all_successors_equivalent = StatementEquality::TrivialEqual;
-
-                // All successor basic blocks must be equal or contain statements that are pairwise considered equal.
-                for ((target_and_value_l,bb_l), (target_and_value_r,bb_r)) in iter_bbs_reachable.tuple_windows() {
-                    let trivial_checks = bb_l.is_cleanup == bb_r.is_cleanup
-                                            && bb_l.terminator().kind == bb_r.terminator().kind
-                                            && bb_l.statements.len() == bb_r.statements.len();
-                    let statement_check = || {
-                        bb_l.statements.iter().zip(&bb_r.statements).try_fold(StatementEquality::TrivialEqual, |acc,(l,r)| {
-                            let stmt_equality = self.statement_equality(*adt_matched_on, &l, target_and_value_l, &r, target_and_value_r);
-                            if matches!(stmt_equality, StatementEquality::NotEqual) {
-                                // short circuit
-                                None
-                            } else {
-                                Some(acc.combine(&stmt_equality))
-                            }
-                        })
-                        .unwrap_or(StatementEquality::NotEqual)
-                    };
-                    if !trivial_checks {
-                        all_successors_equivalent = StatementEquality::NotEqual;
-                        break;
-                    }
-                    all_successors_equivalent = all_successors_equivalent.combine(&statement_check());
-                };
-
-                match all_successors_equivalent{
-                    StatementEquality::TrivialEqual => {
-                        // statements are trivially equal, so just take first
-                        trace!("Statements are trivially equal");
-                        Some(SimplifyBranchSameOptimization {
-                            bb_to_goto: bb_first.target,
-                            bb_to_opt_terminator: bb_idx,
-                        })
-                    }
-                    StatementEquality::ConsideredEqual(bb_to_choose) => {
-                        trace!("Statements are considered equal");
-                        Some(SimplifyBranchSameOptimization {
-                            bb_to_goto: bb_to_choose,
-                            bb_to_opt_terminator: bb_idx,
-                        })
-                    }
-                    StatementEquality::NotEqual => {
-                        trace!("NO: not all successors of basic block {:?} were equivalent", bb_idx);
-                        None
-                    }
-                }
-            })
-            .collect()
-    }
-
-    /// Tests if two statements can be considered equal
-    ///
-    /// Statements can be trivially equal if the kinds match.
-    /// But they can also be considered equal in the following case A:
-    /// ```ignore (MIR)
-    /// discriminant(_0) = 0;   // bb1
-    /// _0 = move _1;           // bb2
-    /// ```
-    /// In this case the two statements are equal iff
-    /// - `_0` is an enum where the variant index 0 is fieldless, and
-    /// -  bb1 was targeted by a switch where the discriminant of `_1` was switched on
-    fn statement_equality(
-        &self,
-        adt_matched_on: Place<'tcx>,
-        x: &Statement<'tcx>,
-        x_target_and_value: &SwitchTargetAndValue,
-        y: &Statement<'tcx>,
-        y_target_and_value: &SwitchTargetAndValue,
-    ) -> StatementEquality {
-        let helper = |rhs: &Rvalue<'tcx>,
-                      place: &Place<'tcx>,
-                      variant_index: VariantIdx,
-                      switch_value: u128,
-                      side_to_choose| {
-            let place_type = place.ty(self.body, self.tcx).ty;
-            let adt = match *place_type.kind() {
-                ty::Adt(adt, _) if adt.is_enum() => adt,
-                _ => return StatementEquality::NotEqual,
-            };
-            // We need to make sure that the switch value that targets the bb with
-            // SetDiscriminant is the same as the variant discriminant.
-            let variant_discr = adt.discriminant_for_variant(self.tcx, variant_index).val;
-            if variant_discr != switch_value {
-                trace!(
-                    "NO: variant discriminant {} does not equal switch value {}",
-                    variant_discr,
-                    switch_value
-                );
-                return StatementEquality::NotEqual;
-            }
-            let variant_is_fieldless = adt.variant(variant_index).fields.is_empty();
-            if !variant_is_fieldless {
-                trace!("NO: variant {:?} was not fieldless", variant_index);
-                return StatementEquality::NotEqual;
-            }
-
-            match rhs {
-                Rvalue::Use(operand) if operand.place() == Some(adt_matched_on) => {
-                    StatementEquality::ConsideredEqual(side_to_choose)
-                }
-                _ => {
-                    trace!(
-                        "NO: RHS of assignment was {:?}, but expected it to match the adt being matched on in the switch, which is {:?}",
-                        rhs,
-                        adt_matched_on
-                    );
-                    StatementEquality::NotEqual
-                }
-            }
-        };
-        match (&x.kind, &y.kind) {
-            // trivial case
-            (x, y) if x == y => StatementEquality::TrivialEqual,
-
-            // check for case A
-            (
-                StatementKind::Assign(box (_, rhs)),
-                &StatementKind::SetDiscriminant { ref place, variant_index },
-            ) if y_target_and_value.value.is_some() => {
-                // choose basic block of x, as that has the assign
-                helper(
-                    rhs,
-                    place,
-                    variant_index,
-                    y_target_and_value.value.unwrap(),
-                    x_target_and_value.target,
-                )
-            }
-            (
-                &StatementKind::SetDiscriminant { ref place, variant_index },
-                &StatementKind::Assign(box (_, ref rhs)),
-            ) if x_target_and_value.value.is_some() => {
-                // choose basic block of y, as that has the assign
-                helper(
-                    rhs,
-                    place,
-                    variant_index,
-                    x_target_and_value.value.unwrap(),
-                    y_target_and_value.target,
-                )
-            }
-            _ => {
-                trace!("NO: statements `{:?}` and `{:?}` not considered equal", x, y);
-                StatementEquality::NotEqual
-            }
-        }
-    }
-}
-
-#[derive(Copy, Clone, Eq, PartialEq)]
-enum StatementEquality {
-    /// The two statements are trivially equal; same kind
-    TrivialEqual,
-    /// The two statements are considered equal, but may be of different kinds. The BasicBlock field is the basic block to jump to when performing the branch-same optimization.
-    /// For example, `_0 = _1` and `discriminant(_0) = discriminant(0)` are considered equal if 0 is a fieldless variant of an enum. But we don't want to jump to the basic block with the SetDiscriminant, as that is not legal if _1 is not the 0 variant index
-    ConsideredEqual(BasicBlock),
-    /// The two statements are not equal
-    NotEqual,
-}
-
-impl StatementEquality {
-    fn combine(&self, other: &StatementEquality) -> StatementEquality {
-        use StatementEquality::*;
-        match (self, other) {
-            (TrivialEqual, TrivialEqual) => TrivialEqual,
-            (TrivialEqual, ConsideredEqual(b)) | (ConsideredEqual(b), TrivialEqual) => {
-                ConsideredEqual(*b)
-            }
-            (ConsideredEqual(b1), ConsideredEqual(b2)) => {
-                if b1 == b2 {
-                    ConsideredEqual(*b1)
-                } else {
-                    NotEqual
-                }
-            }
-            (_, NotEqual) | (NotEqual, _) => NotEqual,
-        }
-    }
-}
index 06b970ad979770b633ed432e5e0e6ed0e6db06ed..40763da0bb5470ce20924fd76da86713e47e21dd 100644 (file)
@@ -337,7 +337,9 @@ pub(crate) struct IfExpressionMissingThenBlock {
     #[primary_span]
     pub if_span: Span,
     #[subdiagnostic]
-    pub sub: IfExpressionMissingThenBlockSub,
+    pub missing_then_block_sub: IfExpressionMissingThenBlockSub,
+    #[subdiagnostic]
+    pub let_else_sub: Option<IfExpressionLetSomeSub>,
 }
 
 #[derive(Subdiagnostic)]
@@ -348,6 +350,13 @@ pub(crate) enum IfExpressionMissingThenBlockSub {
     AddThenBlock(#[primary_span] Span),
 }
 
+#[derive(Subdiagnostic)]
+#[help(parse_extra_if_in_let_else)]
+pub(crate) struct IfExpressionLetSomeSub {
+    #[primary_span]
+    pub if_span: Span,
+}
+
 #[derive(Diagnostic)]
 #[diag(parse_if_expression_missing_condition)]
 pub(crate) struct IfExpressionMissingCondition {
index 4c918c6702ed9b19f3a2ed08af51506c50e17666..eda7046c748e5f52121854349a3fa6f903e502d2 100644 (file)
@@ -2372,7 +2372,7 @@ pub fn dummy_const_arg_needs_braces(
 
     /// Some special error handling for the "top-level" patterns in a match arm,
     /// `for` loop, `let`, &c. (in contrast to subpatterns within such).
-    pub(crate) fn maybe_recover_colon_colon_in_pat_typo(
+    pub(crate) fn maybe_recover_colon_colon_in_pat_typo_or_anon_enum(
         &mut self,
         mut first_pat: P<Pat>,
         expected: Expected,
@@ -2383,26 +2383,41 @@ pub(crate) fn maybe_recover_colon_colon_in_pat_typo(
         if !matches!(first_pat.kind, PatKind::Ident(_, _, None) | PatKind::Path(..))
             || !self.look_ahead(1, |token| token.is_ident() && !token.is_reserved_ident())
         {
+            let mut snapshot_type = self.create_snapshot_for_diagnostic();
+            snapshot_type.bump(); // `:`
+            match snapshot_type.parse_ty() {
+                Err(inner_err) => {
+                    inner_err.cancel();
+                }
+                Ok(ty) => {
+                    let Err(mut err) = self.expected_one_of_not_found(&[], &[]) else {
+                        return first_pat;
+                    };
+                    err.span_label(ty.span, "specifying the type of a pattern isn't supported");
+                    self.restore_snapshot(snapshot_type);
+                    let span = first_pat.span.to(ty.span);
+                    first_pat = self.mk_pat(span, PatKind::Wild);
+                    err.emit();
+                }
+            }
             return first_pat;
         }
         // The pattern looks like it might be a path with a `::` -> `:` typo:
         // `match foo { bar:baz => {} }`
-        let span = self.token.span;
+        let colon_span = self.token.span;
         // We only emit "unexpected `:`" error here if we can successfully parse the
         // whole pattern correctly in that case.
-        let snapshot = self.create_snapshot_for_diagnostic();
+        let mut snapshot_pat = self.create_snapshot_for_diagnostic();
+        let mut snapshot_type = self.create_snapshot_for_diagnostic();
 
         // Create error for "unexpected `:`".
         match self.expected_one_of_not_found(&[], &[]) {
             Err(mut err) => {
-                self.bump(); // Skip the `:`.
-                match self.parse_pat_no_top_alt(expected) {
+                snapshot_pat.bump(); // Skip the `:`.
+                snapshot_type.bump(); // Skip the `:`.
+                match snapshot_pat.parse_pat_no_top_alt(expected) {
                     Err(inner_err) => {
-                        // Carry on as if we had not done anything, callers will emit a
-                        // reasonable error.
                         inner_err.cancel();
-                        err.cancel();
-                        self.restore_snapshot(snapshot);
                     }
                     Ok(mut pat) => {
                         // We've parsed the rest of the pattern.
@@ -2466,8 +2481,8 @@ pub(crate) fn maybe_recover_colon_colon_in_pat_typo(
                             _ => {}
                         }
                         if show_sugg {
-                            err.span_suggestion(
-                                span,
+                            err.span_suggestion_verbose(
+                                colon_span.until(self.look_ahead(1, |t| t.span)),
                                 "maybe write a path separator here",
                                 "::",
                                 Applicability::MaybeIncorrect,
@@ -2475,13 +2490,24 @@ pub(crate) fn maybe_recover_colon_colon_in_pat_typo(
                         } else {
                             first_pat = self.mk_pat(new_span, PatKind::Wild);
                         }
-                        err.emit();
+                        self.restore_snapshot(snapshot_pat);
                     }
                 }
+                match snapshot_type.parse_ty() {
+                    Err(inner_err) => {
+                        inner_err.cancel();
+                    }
+                    Ok(ty) => {
+                        err.span_label(ty.span, "specifying the type of a pattern isn't supported");
+                        self.restore_snapshot(snapshot_type);
+                        let new_span = first_pat.span.to(ty.span);
+                        first_pat = self.mk_pat(new_span, PatKind::Wild);
+                    }
+                }
+                err.emit();
             }
             _ => {
                 // Carry on as if we had not done anything. This should be unreachable.
-                self.restore_snapshot(snapshot);
             }
         };
         first_pat
index bf93a89f065557efc5535cc75ad9ad1233047d8b..3225a309a319b6286ce8baf02c8a3dd63a23a4cb 100644 (file)
     ComparisonOrShiftInterpretedAsGenericSugg, DoCatchSyntaxRemoved, DotDotDot, EqFieldInit,
     ExpectedElseBlock, ExpectedEqForLetExpr, ExpectedExpressionFoundLet,
     FieldExpressionWithGeneric, FloatLiteralRequiresIntegerPart, FoundExprWouldBeStmt,
-    IfExpressionMissingCondition, IfExpressionMissingThenBlock, IfExpressionMissingThenBlockSub,
-    InvalidBlockMacroSegment, InvalidComparisonOperator, InvalidComparisonOperatorSub,
-    InvalidInterpolatedExpression, InvalidLiteralSuffixOnTupleIndex, InvalidLogicalOperator,
-    InvalidLogicalOperatorSub, LabeledLoopInBreak, LeadingPlusNotSupported, LeftArrowOperator,
-    LifetimeInBorrowExpression, MacroInvocationWithQualifiedPath, MalformedLoopLabel,
-    MatchArmBodyWithoutBraces, MatchArmBodyWithoutBracesSugg, MissingCommaAfterMatchArm,
-    MissingDotDot, MissingInInForLoop, MissingInInForLoopSub, MissingSemicolonBeforeArray,
-    NoFieldsForFnCall, NotAsNegationOperator, NotAsNegationOperatorSub,
-    OuterAttributeNotAllowedOnIfElse, ParenthesesWithStructFields,
+    IfExpressionLetSomeSub, IfExpressionMissingCondition, IfExpressionMissingThenBlock,
+    IfExpressionMissingThenBlockSub, InvalidBlockMacroSegment, InvalidComparisonOperator,
+    InvalidComparisonOperatorSub, InvalidInterpolatedExpression, InvalidLiteralSuffixOnTupleIndex,
+    InvalidLogicalOperator, InvalidLogicalOperatorSub, LabeledLoopInBreak, LeadingPlusNotSupported,
+    LeftArrowOperator, LifetimeInBorrowExpression, MacroInvocationWithQualifiedPath,
+    MalformedLoopLabel, MatchArmBodyWithoutBraces, MatchArmBodyWithoutBracesSugg,
+    MissingCommaAfterMatchArm, MissingDotDot, MissingInInForLoop, MissingInInForLoopSub,
+    MissingSemicolonBeforeArray, NoFieldsForFnCall, NotAsNegationOperator,
+    NotAsNegationOperatorSub, OuterAttributeNotAllowedOnIfElse, ParenthesesWithStructFields,
     RequireColonAfterLabeledExpression, ShiftInterpretedAsGeneric, StructLiteralNotAllowedHere,
     StructLiteralNotAllowedHereSugg, TildeAsUnaryOperator, UnexpectedIfWithIf,
     UnexpectedTokenAfterLabel, UnexpectedTokenAfterLabelSugg, WrapExpressionInParentheses,
@@ -2251,9 +2251,10 @@ fn parse_if_after_cond(&mut self, lo: Span, mut cond: P<Expr>) -> PResult<'a, P<
                     if let ExprKind::Block(_, None) = right.kind => {
                         self.sess.emit_err(IfExpressionMissingThenBlock {
                             if_span: lo,
-                            sub: IfExpressionMissingThenBlockSub::UnfinishedCondition(
-                                cond_span.shrink_to_lo().to(*binop_span)
-                            ),
+                            missing_then_block_sub:
+                                IfExpressionMissingThenBlockSub::UnfinishedCondition(cond_span.shrink_to_lo().to(*binop_span)),
+                                let_else_sub: None,
+
                         });
                         std::mem::replace(right, this.mk_expr_err(binop_span.shrink_to_hi()))
                     },
@@ -2279,9 +2280,15 @@ fn parse_if_after_cond(&mut self, lo: Span, mut cond: P<Expr>) -> PResult<'a, P<
             if let Some(block) = recover_block_from_condition(self) {
                 block
             } else {
+                let let_else_sub = matches!(cond.kind, ExprKind::Let(..))
+                    .then(|| IfExpressionLetSomeSub { if_span: lo });
+
                 self.sess.emit_err(IfExpressionMissingThenBlock {
                     if_span: lo,
-                    sub: IfExpressionMissingThenBlockSub::AddThenBlock(cond_span.shrink_to_hi()),
+                    missing_then_block_sub: IfExpressionMissingThenBlockSub::AddThenBlock(
+                        cond_span.shrink_to_hi(),
+                    ),
+                    let_else_sub,
                 });
                 self.mk_block_err(cond_span.shrink_to_hi())
             }
index e73a17ced7deb2598f52a013189ee3392e379547..e5411538eea220ce5ff179026be98d677b08dc67 100644 (file)
@@ -116,7 +116,8 @@ fn parse_pat_allow_top_alt_inner(
 
             // Check if the user wrote `foo:bar` instead of `foo::bar`.
             if ra == RecoverColon::Yes {
-                first_pat = self.maybe_recover_colon_colon_in_pat_typo(first_pat, expected);
+                first_pat =
+                    self.maybe_recover_colon_colon_in_pat_typo_or_anon_enum(first_pat, expected);
             }
 
             if let Some(leading_vert_span) = leading_vert_span {
index 1766b0293de52a33c2eceb3254ecfe0b44e7f0af..25de0a9e75014ae019b680aedaf410e4563bcc5d 100644 (file)
@@ -11,6 +11,7 @@
     self as ast, BareFnTy, FnRetTy, GenericBound, GenericBounds, GenericParam, Generics, Lifetime,
     MacCall, MutTy, Mutability, PolyTraitRef, TraitBoundModifier, TraitObjectSyntax, Ty, TyKind,
 };
+use rustc_ast_pretty::pprust;
 use rustc_errors::{pluralize, struct_span_err, Applicability, PResult};
 use rustc_span::source_map::Span;
 use rustc_span::symbol::{kw, sym, Ident};
@@ -43,17 +44,24 @@ pub(super) enum AllowPlus {
     No,
 }
 
-#[derive(PartialEq)]
+#[derive(PartialEq, Clone, Copy)]
 pub(super) enum RecoverQPath {
     Yes,
     No,
 }
 
+#[derive(PartialEq, Clone, Copy)]
 pub(super) enum RecoverQuestionMark {
     Yes,
     No,
 }
 
+#[derive(PartialEq, Clone, Copy)]
+pub(super) enum RecoverAnonEnum {
+    Yes,
+    No,
+}
+
 /// Signals whether parsing a type should recover `->`.
 ///
 /// More specifically, when parsing a function like:
@@ -86,7 +94,7 @@ fn can_recover(self, token: &TokenKind) -> bool {
 }
 
 // Is `...` (`CVarArgs`) legal at this level of type parsing?
-#[derive(PartialEq)]
+#[derive(PartialEq, Clone, Copy)]
 enum AllowCVariadic {
     Yes,
     No,
@@ -111,6 +119,7 @@ pub fn parse_ty(&mut self) -> PResult<'a, P<Ty>> {
             RecoverReturnSign::Yes,
             None,
             RecoverQuestionMark::Yes,
+            RecoverAnonEnum::No,
         )
     }
 
@@ -125,6 +134,7 @@ pub(super) fn parse_ty_with_generics_recovery(
             RecoverReturnSign::Yes,
             Some(ty_params),
             RecoverQuestionMark::Yes,
+            RecoverAnonEnum::No,
         )
     }
 
@@ -139,6 +149,7 @@ pub(super) fn parse_ty_for_param(&mut self) -> PResult<'a, P<Ty>> {
             RecoverReturnSign::Yes,
             None,
             RecoverQuestionMark::Yes,
+            RecoverAnonEnum::Yes,
         )
     }
 
@@ -156,6 +167,7 @@ pub(super) fn parse_ty_no_plus(&mut self) -> PResult<'a, P<Ty>> {
             RecoverReturnSign::Yes,
             None,
             RecoverQuestionMark::Yes,
+            RecoverAnonEnum::No,
         )
     }
 
@@ -169,6 +181,7 @@ pub(super) fn parse_as_cast_ty(&mut self) -> PResult<'a, P<Ty>> {
             RecoverReturnSign::Yes,
             None,
             RecoverQuestionMark::No,
+            RecoverAnonEnum::No,
         )
     }
 
@@ -180,6 +193,7 @@ pub(super) fn parse_no_question_mark_recover(&mut self) -> PResult<'a, P<Ty>> {
             RecoverReturnSign::Yes,
             None,
             RecoverQuestionMark::No,
+            RecoverAnonEnum::No,
         )
     }
 
@@ -192,6 +206,7 @@ pub(super) fn parse_ty_for_where_clause(&mut self) -> PResult<'a, P<Ty>> {
             RecoverReturnSign::OnlyFatArrow,
             None,
             RecoverQuestionMark::Yes,
+            RecoverAnonEnum::No,
         )
     }
 
@@ -211,6 +226,7 @@ pub(super) fn parse_ret_ty(
                 recover_return_sign,
                 None,
                 RecoverQuestionMark::Yes,
+                RecoverAnonEnum::Yes,
             )?;
             FnRetTy::Ty(ty)
         } else if recover_return_sign.can_recover(&self.token.kind) {
@@ -232,6 +248,7 @@ pub(super) fn parse_ret_ty(
                 recover_return_sign,
                 None,
                 RecoverQuestionMark::Yes,
+                RecoverAnonEnum::Yes,
             )?;
             FnRetTy::Ty(ty)
         } else {
@@ -247,6 +264,7 @@ fn parse_ty_common(
         recover_return_sign: RecoverReturnSign,
         ty_generics: Option<&Generics>,
         recover_question_mark: RecoverQuestionMark,
+        recover_anon_enum: RecoverAnonEnum,
     ) -> PResult<'a, P<Ty>> {
         let allow_qpath_recovery = recover_qpath == RecoverQPath::Yes;
         maybe_recover_from_interpolated_ty_qpath!(self, allow_qpath_recovery);
@@ -325,14 +343,55 @@ fn parse_ty_common(
         let mut ty = self.mk_ty(span, kind);
 
         // Try to recover from use of `+` with incorrect priority.
-        if matches!(allow_plus, AllowPlus::Yes) {
+        if allow_plus == AllowPlus::Yes {
             self.maybe_recover_from_bad_type_plus(&ty)?;
         } else {
             self.maybe_report_ambiguous_plus(impl_dyn_multi, &ty);
         }
-        if let RecoverQuestionMark::Yes = recover_question_mark {
+        if RecoverQuestionMark::Yes == recover_question_mark {
             ty = self.maybe_recover_from_question_mark(ty);
         }
+        if recover_anon_enum == RecoverAnonEnum::Yes
+            && self.check_noexpect(&token::BinOp(token::Or))
+            && self.look_ahead(1, |t| t.can_begin_type())
+        {
+            let mut pipes = vec![self.token.span];
+            let mut types = vec![ty];
+            loop {
+                if !self.eat(&token::BinOp(token::Or)) {
+                    break;
+                }
+                pipes.push(self.prev_token.span);
+                types.push(self.parse_ty_common(
+                    allow_plus,
+                    allow_c_variadic,
+                    recover_qpath,
+                    recover_return_sign,
+                    ty_generics,
+                    recover_question_mark,
+                    RecoverAnonEnum::No,
+                )?);
+            }
+            let mut err = self.struct_span_err(pipes, "anonymous enums are not supported");
+            for ty in &types {
+                err.span_label(ty.span, "");
+            }
+            err.help(&format!(
+                "create a named `enum` and use it here instead:\nenum Name {{\n{}\n}}",
+                types
+                    .iter()
+                    .enumerate()
+                    .map(|(i, t)| format!(
+                        "    Variant{}({}),",
+                        i + 1, // Lets not confuse people with zero-indexing :)
+                        pprust::to_string(|s| s.print_type(&t)),
+                    ))
+                    .collect::<Vec<_>>()
+                    .join("\n"),
+            ));
+            err.emit();
+            return Ok(self.mk_ty(lo.to(self.prev_token.span), TyKind::Err));
+        }
         if allow_qpath_recovery { self.maybe_recover_from_bad_qpath(ty) } else { Ok(ty) }
     }
 
index f9f9799d3e4f2058bf9911a23a60c22d9cf2837f..42329853259459ead163c2e4e7c70fc28084be19 100644 (file)
@@ -6,11 +6,12 @@
 
 use crate::errors::{
     self, AttrApplication, DebugVisualizerUnreadable, InvalidAttrAtCrateLevel, ObjectLifetimeErr,
-    OnlyHasEffectOn, TransparentIncompatible, UnrecognizedReprHint,
+    OnlyHasEffectOn, ProcMacroDiffArguments, ProcMacroInvalidAbi, ProcMacroMissingArguments,
+    ProcMacroTypeError, ProcMacroUnsafe, TransparentIncompatible, UnrecognizedReprHint,
 };
 use rustc_ast::{ast, AttrStyle, Attribute, LitKind, MetaItemKind, MetaItemLit, NestedMetaItem};
 use rustc_data_structures::fx::FxHashMap;
-use rustc_errors::{fluent, Applicability, MultiSpan};
+use rustc_errors::{fluent, Applicability, IntoDiagnosticArg, MultiSpan};
 use rustc_expand::base::resolve_path;
 use rustc_feature::{AttributeDuplicates, AttributeType, BuiltinAttribute, BUILTIN_ATTRIBUTE_MAP};
 use rustc_hir as hir;
 use rustc_hir::{
     self, FnSig, ForeignItem, HirId, Item, ItemKind, TraitItem, CRATE_HIR_ID, CRATE_OWNER_ID,
 };
-use rustc_hir::{MethodKind, Target};
+use rustc_hir::{MethodKind, Target, Unsafety};
 use rustc_middle::hir::nested_filter;
 use rustc_middle::middle::resolve_lifetime::ObjectLifetimeDefault;
+use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams};
 use rustc_middle::ty::query::Providers;
-use rustc_middle::ty::TyCtxt;
+use rustc_middle::ty::{ParamEnv, TyCtxt};
 use rustc_session::lint::builtin::{
     CONFLICTING_REPR_HINTS, INVALID_DOC_ATTRIBUTES, UNUSED_ATTRIBUTES,
 };
@@ -31,6 +33,7 @@
 use rustc_span::symbol::{kw, sym, Symbol};
 use rustc_span::{Span, DUMMY_SP};
 use rustc_target::spec::abi::Abi;
+use std::cell::Cell;
 use std::collections::hash_map::Entry;
 
 pub(crate) fn target_from_impl_item<'tcx>(
@@ -62,8 +65,29 @@ enum ItemLike<'tcx> {
     ForeignItem,
 }
 
+#[derive(Copy, Clone)]
+pub(crate) enum ProcMacroKind {
+    FunctionLike,
+    Derive,
+    Attribute,
+}
+
+impl IntoDiagnosticArg for ProcMacroKind {
+    fn into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue<'static> {
+        match self {
+            ProcMacroKind::Attribute => "attribute proc macro",
+            ProcMacroKind::Derive => "derive proc macro",
+            ProcMacroKind::FunctionLike => "function-like proc macro",
+        }
+        .into_diagnostic_arg()
+    }
+}
+
 struct CheckAttrVisitor<'tcx> {
     tcx: TyCtxt<'tcx>,
+
+    // Whether or not this visitor should abort after finding errors
+    abort: Cell<bool>,
 }
 
 impl CheckAttrVisitor<'_> {
@@ -173,7 +197,7 @@ fn check_attributes(
                 sym::path => self.check_generic_attr(hir_id, attr, target, Target::Mod),
                 sym::plugin_registrar => self.check_plugin_registrar(hir_id, attr, target),
                 sym::macro_export => self.check_macro_export(hir_id, attr, target),
-                sym::ignore | sym::should_panic | sym::proc_macro_derive => {
+                sym::ignore | sym::should_panic => {
                     self.check_generic_attr(hir_id, attr, target, Target::Fn)
                 }
                 sym::automatically_derived => {
@@ -183,6 +207,16 @@ fn check_attributes(
                     self.check_generic_attr(hir_id, attr, target, Target::Mod)
                 }
                 sym::rustc_object_lifetime_default => self.check_object_lifetime_default(hir_id),
+                sym::proc_macro => {
+                    self.check_proc_macro(hir_id, target, ProcMacroKind::FunctionLike)
+                }
+                sym::proc_macro_attribute => {
+                    self.check_proc_macro(hir_id, target, ProcMacroKind::Attribute);
+                }
+                sym::proc_macro_derive => {
+                    self.check_generic_attr(hir_id, attr, target, Target::Fn);
+                    self.check_proc_macro(hir_id, target, ProcMacroKind::Derive)
+                }
                 _ => {}
             }
 
@@ -2063,6 +2097,103 @@ fn check_unused_attribute(&self, hir_id: HirId, attr: &Attribute) {
             errors::Unused { attr_span: attr.span, note },
         );
     }
+
+    /// A best effort attempt to create an error for a mismatching proc macro signature.
+    ///
+    /// If this best effort goes wrong, it will just emit a worse error later (see #102923)
+    fn check_proc_macro(&self, hir_id: HirId, target: Target, kind: ProcMacroKind) {
+        let expected_input_count = match kind {
+            ProcMacroKind::Attribute => 2,
+            ProcMacroKind::Derive | ProcMacroKind::FunctionLike => 1,
+        };
+
+        let expected_signature = match kind {
+            ProcMacroKind::Attribute => "fn(TokenStream, TokenStream) -> TokenStream",
+            ProcMacroKind::Derive | ProcMacroKind::FunctionLike => "fn(TokenStream) -> TokenStream",
+        };
+
+        let tcx = self.tcx;
+        if target == Target::Fn {
+            let Some(tokenstream) = tcx.get_diagnostic_item(sym::TokenStream) else {return};
+            let tokenstream = tcx.type_of(tokenstream);
+
+            let id = hir_id.expect_owner();
+            let hir_sig = tcx.hir().fn_sig_by_hir_id(hir_id).unwrap();
+
+            let sig = tcx.liberate_late_bound_regions(id.to_def_id(), tcx.fn_sig(id));
+            let sig = tcx.normalize_erasing_regions(ParamEnv::empty(), sig);
+
+            // We don't currently require that the function signature is equal to
+            // `fn(TokenStream) -> TokenStream`, but instead monomorphizes to
+            // `fn(TokenStream) -> TokenStream` after some substitution of generic arguments.
+            //
+            // Properly checking this means pulling in additional `rustc` crates, so we don't.
+            let drcx = DeepRejectCtxt { treat_obligation_params: TreatParams::AsInfer };
+
+            if sig.abi != Abi::Rust {
+                tcx.sess.emit_err(ProcMacroInvalidAbi { span: hir_sig.span, abi: sig.abi.name() });
+                self.abort.set(true);
+            }
+
+            if sig.unsafety == Unsafety::Unsafe {
+                tcx.sess.emit_err(ProcMacroUnsafe { span: hir_sig.span });
+                self.abort.set(true);
+            }
+
+            let output = sig.output();
+
+            // Typecheck the output
+            if !drcx.types_may_unify(output, tokenstream) {
+                tcx.sess.emit_err(ProcMacroTypeError {
+                    span: hir_sig.decl.output.span(),
+                    found: output,
+                    kind,
+                    expected_signature,
+                });
+                self.abort.set(true);
+            }
+
+            if sig.inputs().len() < expected_input_count {
+                tcx.sess.emit_err(ProcMacroMissingArguments {
+                    expected_input_count,
+                    span: hir_sig.span,
+                    kind,
+                    expected_signature,
+                });
+                self.abort.set(true);
+            }
+
+            // Check that the inputs are correct, if there are enough.
+            if sig.inputs().len() >= expected_input_count {
+                for (arg, input) in
+                    sig.inputs().iter().zip(hir_sig.decl.inputs).take(expected_input_count)
+                {
+                    if !drcx.types_may_unify(*arg, tokenstream) {
+                        tcx.sess.emit_err(ProcMacroTypeError {
+                            span: input.span,
+                            found: *arg,
+                            kind,
+                            expected_signature,
+                        });
+                        self.abort.set(true);
+                    }
+                }
+            }
+
+            // Check that there are not too many arguments
+            let body_id = tcx.hir().body_owned_by(id.def_id);
+            let excess = tcx.hir().body(body_id).params.get(expected_input_count..);
+            if let Some(excess @ [begin @ end] | excess @ [begin, .., end]) = excess {
+                tcx.sess.emit_err(ProcMacroDiffArguments {
+                    span: begin.span.to(end.span),
+                    count: excess.len(),
+                    kind,
+                    expected_signature,
+                });
+                self.abort.set(true);
+            }
+        }
+    }
 }
 
 impl<'tcx> Visitor<'tcx> for CheckAttrVisitor<'tcx> {
@@ -2225,12 +2356,15 @@ fn check_non_exported_macro_for_invalid_attrs(tcx: TyCtxt<'_>, item: &Item<'_>)
 }
 
 fn check_mod_attrs(tcx: TyCtxt<'_>, module_def_id: LocalDefId) {
-    let check_attr_visitor = &mut CheckAttrVisitor { tcx };
+    let check_attr_visitor = &mut CheckAttrVisitor { tcx, abort: Cell::new(false) };
     tcx.hir().visit_item_likes_in_module(module_def_id, check_attr_visitor);
     if module_def_id.is_top_level_module() {
         check_attr_visitor.check_attributes(CRATE_HIR_ID, DUMMY_SP, Target::Mod, None);
         check_invalid_crate_level_attr(tcx, tcx.hir().krate_attrs());
     }
+    if check_attr_visitor.abort.get() {
+        tcx.sess.abort_if_errors()
+    }
 }
 
 pub(crate) fn provide(providers: &mut Providers) {
index aa726d6cd92aad0b9a7ce3374f23c64c944fe7d1..dd8c646a43c82e837b0393155f7660931147e0d1 100644 (file)
@@ -48,7 +48,7 @@ fn required_feature_gates(self) -> Option<&'static [Symbol]> {
             Self::Match(TryDesugar) => &[sym::const_try],
 
             // All other expressions are allowed.
-            Self::Loop(Loop | While) | Self::Match(Normal) => &[],
+            Self::Loop(Loop | While) | Self::Match(Normal | FormatArgs) => &[],
         };
 
         Some(gates)
index 9c6519ea4bb24be91a133b22d716ca376593ae4d..9e05ad22e624172681d1b249710a71f669297cbf 100644 (file)
@@ -12,6 +12,7 @@
 use rustc_middle::ty::{MainDefinition, Ty};
 use rustc_span::{Span, Symbol, DUMMY_SP};
 
+use crate::check_attr::ProcMacroKind;
 use crate::lang_items::Duplicate;
 
 #[derive(Diagnostic)]
@@ -1515,3 +1516,52 @@ pub struct ChangeFieldsToBeOfUnitType {
     #[suggestion_part(code = "()")]
     pub spans: Vec<Span>,
 }
+
+#[derive(Diagnostic)]
+#[diag(passes_proc_macro_typeerror)]
+#[note]
+pub(crate) struct ProcMacroTypeError<'tcx> {
+    #[primary_span]
+    #[label]
+    pub span: Span,
+    pub found: Ty<'tcx>,
+    pub kind: ProcMacroKind,
+    pub expected_signature: &'static str,
+}
+
+#[derive(Diagnostic)]
+#[diag(passes_proc_macro_diff_arg_count)]
+pub(crate) struct ProcMacroDiffArguments {
+    #[primary_span]
+    #[label]
+    pub span: Span,
+    pub count: usize,
+    pub kind: ProcMacroKind,
+    pub expected_signature: &'static str,
+}
+
+#[derive(Diagnostic)]
+#[diag(passes_proc_macro_missing_args)]
+pub(crate) struct ProcMacroMissingArguments {
+    #[primary_span]
+    #[label]
+    pub span: Span,
+    pub expected_input_count: usize,
+    pub kind: ProcMacroKind,
+    pub expected_signature: &'static str,
+}
+
+#[derive(Diagnostic)]
+#[diag(passes_proc_macro_invalid_abi)]
+pub(crate) struct ProcMacroInvalidAbi {
+    #[primary_span]
+    pub span: Span,
+    pub abi: &'static str,
+}
+
+#[derive(Diagnostic)]
+#[diag(passes_proc_macro_unsafe)]
+pub(crate) struct ProcMacroUnsafe {
+    #[primary_span]
+    pub span: Span,
+}
index b86d2316820cec75ab3fa744079775fa22151d6c..d1b896e940e6e7d6f054b22c2ac7bc0f98e8b592 100644 (file)
@@ -567,7 +567,7 @@ fn visit_expr(&mut self, e: &'v ast::Expr) {
                 Box, Array, ConstBlock, Call, MethodCall, Tup, Binary, Unary, Lit, Cast, Type, Let,
                 If, While, ForLoop, Loop, Match, Closure, Block, Async, Await, TryBlock, Assign,
                 AssignOp, Field, Index, Range, Underscore, Path, AddrOf, Break, Continue, Ret,
-                InlineAsm, MacCall, Struct, Repeat, Paren, Try, Yield, Yeet, IncludedBytes, Err
+                InlineAsm, FormatArgs, MacCall, Struct, Repeat, Paren, Try, Yield, Yeet, IncludedBytes, Err
             ]
         );
         ast_visit::walk_expr(self, e)
index 6d448433ee6dbc940bdcde726b3a9f25efbe8997..37beff37c1fb9d988c33ae968afa86fb96370603 100644 (file)
@@ -227,20 +227,27 @@ fn make_base_error(
                     && let Some(FnCtxt::Assoc(_)) = fn_kind.ctxt()
                     && let Some(items) = self.diagnostic_metadata.current_impl_items
                     && let Some(item) = items.iter().find(|i| {
-                        if let AssocItemKind::Fn(_) = &i.kind && i.ident.name == item_str.name
+                        if let AssocItemKind::Fn(..) | AssocItemKind::Const(..) = &i.kind
+                            && i.ident.name == item_str.name
                         {
                             debug!(?item_str.name);
                             return true
                         }
                         false
                     })
-                    && let AssocItemKind::Fn(fn_) = &item.kind
                 {
-                    debug!(?fn_);
-                    let self_sugg = if fn_.sig.decl.has_self() { "self." } else { "Self::" };
+                    let self_sugg = match &item.kind {
+                        AssocItemKind::Fn(fn_) if fn_.sig.decl.has_self() => "self.",
+                        _ => "Self::",
+                    };
+
                     Some((
                         item_span.shrink_to_lo(),
-                        "consider using the associated function",
+                        match &item.kind {
+                            AssocItemKind::Fn(..) => "consider using the associated function",
+                            AssocItemKind::Const(..) => "consider using the associated constant",
+                            _ => unreachable!("item kind was filtered above"),
+                        },
                         self_sugg.to_string()
                     ))
                 } else {
index 09bd474688bf2874ba0a3e7ae1a00e0d57d51e1f..db95b8bca2f8ce78791f77dfd1cb801dd9151c50 100644 (file)
@@ -864,18 +864,6 @@ pub enum CrateType {
     ProcMacro,
 }
 
-impl CrateType {
-    /// When generated, is this crate type an archive?
-    pub fn is_archive(&self) -> bool {
-        match *self {
-            CrateType::Rlib | CrateType::Staticlib => true,
-            CrateType::Executable | CrateType::Dylib | CrateType::Cdylib | CrateType::ProcMacro => {
-                false
-            }
-        }
-    }
-}
-
 #[derive(Clone, Hash, Debug, PartialEq, Eq)]
 pub enum Passes {
     Some(Vec<String>),
index 7597b8d126a9ceb55375ecdb2f9f523cd756e093..30ca0b8060d22b2bdfbd5668aafe03c41ff20109 100644 (file)
         Target,
         ToOwned,
         ToString,
+        TokenStream,
         Try,
         TryCaptureGeneric,
         TryCapturePrintable,
         forbid,
         forget,
         format,
+        format_alignment,
         format_args,
         format_args_capture,
         format_args_macro,
         format_args_nl,
+        format_argument,
+        format_arguments,
+        format_count,
         format_macro,
+        format_placeholder,
+        format_unsafe_arg,
         freeze,
         freg,
         frem_fast,
index 4a2d39cc70023bbb81b49c3ba06413273b85e9f0..247256f076ba9b195c6cbe1286387b4ba7a9c3f8 100644 (file)
@@ -39,7 +39,7 @@ fn should_use_fp_conv_helper<'a, Ty, C>(
 {
     match arg_layout.abi {
         Abi::Scalar(scalar) => match scalar.primitive() {
-            abi::Int(..) | abi::Pointer => {
+            abi::Int(..) | abi::Pointer(_) => {
                 if arg_layout.size.bits() > xlen {
                     return Err(CannotUseFpConv);
                 }
index 3b8c867d35ba37b3a06e41b64b90123c19f514d6..a0730fbb650dc9b4527882bbe232afa1ed17201b 100644 (file)
@@ -346,7 +346,7 @@ pub fn homogeneous_aggregate<C>(&self, cx: &C) -> Result<HomogeneousAggregate, H
             // The primitive for this algorithm.
             Abi::Scalar(scalar) => {
                 let kind = match scalar.primitive() {
-                    abi::Int(..) | abi::Pointer => RegKind::Integer,
+                    abi::Int(..) | abi::Pointer(_) => RegKind::Integer,
                     abi::F32 | abi::F64 => RegKind::Float,
                 };
                 Ok(HomogeneousAggregate::Homogeneous(Reg { kind, size: self.size }))
index 34280d38e3406a7bef5f4e00839b993f88f10eec..d90dce2a08785cbd2e6995bfb5f16fd9acc77f7d 100644 (file)
@@ -45,7 +45,7 @@ fn should_use_fp_conv_helper<'a, Ty, C>(
 {
     match arg_layout.abi {
         Abi::Scalar(scalar) => match scalar.primitive() {
-            abi::Int(..) | abi::Pointer => {
+            abi::Int(..) | abi::Pointer(_) => {
                 if arg_layout.size.bits() > xlen {
                     return Err(CannotUseFpConv);
                 }
index c8b6ac5ae25b2eb60152c2f3ae166471d0bb3f58..cbed5b4afc134931a0ba5851f90218399775b5b4 100644 (file)
@@ -20,7 +20,7 @@ fn arg_scalar<C>(cx: &C, scalar: &Scalar, offset: Size, mut data: Sdata) -> Sdat
 {
     let dl = cx.data_layout();
 
-    if !scalar.primitive().is_float() {
+    if !matches!(scalar.primitive(), abi::F32 | abi::F64) {
         return data;
     }
 
@@ -83,11 +83,11 @@ fn arg_scalar_pair<C>(
         (abi::F32, _) => offset += Reg::f32().size,
         (_, abi::F64) => offset += Reg::f64().size,
         (abi::Int(i, _signed), _) => offset += i.size(),
-        (abi::Pointer, _) => offset += Reg::i64().size,
+        (abi::Pointer(_), _) => offset += Reg::i64().size,
         _ => {}
     }
 
-    if (offset.bytes() % 4) != 0 && scalar2.primitive().is_float() {
+    if (offset.bytes() % 4) != 0 && matches!(scalar2.primitive(), abi::F32 | abi::F64) {
         offset += Size::from_bytes(4 - (offset.bytes() % 4));
     }
     data = arg_scalar(cx, scalar2, offset, data);
index c0c071a614f5058808e7bbd11384287ca9139e6e..9427f27d1b7bb327893a287c1d83db37822159b3 100644 (file)
@@ -50,7 +50,7 @@ fn classify<'a, Ty, C>(
             Abi::Uninhabited => return Ok(()),
 
             Abi::Scalar(scalar) => match scalar.primitive() {
-                abi::Int(..) | abi::Pointer => Class::Int,
+                abi::Int(..) | abi::Pointer(_) => Class::Int,
                 abi::F32 | abi::F64 => Class::Sse,
             },
 
index 88a0a1f8ecfdedafd60a8d9f6f516f488f06ca79..39761baf1bc2919401d823dc4d17aaae56d59195 100644 (file)
@@ -129,7 +129,7 @@ pub fn is_single_fp_element<C>(self, cx: &C) -> bool
         C: HasDataLayout,
     {
         match self.abi {
-            Abi::Scalar(scalar) => scalar.primitive().is_float(),
+            Abi::Scalar(scalar) => matches!(scalar.primitive(), F32 | F64),
             Abi::Aggregate { .. } => {
                 if self.fields.count() == 1 && self.fields.offset(0).bytes() == 0 {
                     self.field(cx, 0).is_single_fp_element(cx)
index cdb72d49834f0101f401660171e102675bfa9e3b..d23b550621e17421ce179a63a98a4445ec4f3402 100644 (file)
@@ -133,6 +133,21 @@ fn consider_builtin_tuple_candidate(
         ecx: &mut EvalCtxt<'_, 'tcx>,
         goal: Goal<'tcx, Self>,
     ) -> QueryResult<'tcx>;
+
+    fn consider_builtin_pointee_candidate(
+        ecx: &mut EvalCtxt<'_, 'tcx>,
+        goal: Goal<'tcx, Self>,
+    ) -> QueryResult<'tcx>;
+
+    fn consider_builtin_future_candidate(
+        ecx: &mut EvalCtxt<'_, 'tcx>,
+        goal: Goal<'tcx, Self>,
+    ) -> QueryResult<'tcx>;
+
+    fn consider_builtin_generator_candidate(
+        ecx: &mut EvalCtxt<'_, 'tcx>,
+        goal: Goal<'tcx, Self>,
+    ) -> QueryResult<'tcx>;
 }
 
 impl<'tcx> EvalCtxt<'_, 'tcx> {
@@ -259,6 +274,12 @@ fn assemble_builtin_impl_candidates<G: GoalKind<'tcx>>(
             G::consider_builtin_fn_trait_candidates(self, goal, kind)
         } else if lang_items.tuple_trait() == Some(trait_def_id) {
             G::consider_builtin_tuple_candidate(self, goal)
+        } else if lang_items.pointee_trait() == Some(trait_def_id) {
+            G::consider_builtin_pointee_candidate(self, goal)
+        } else if lang_items.future_trait() == Some(trait_def_id) {
+            G::consider_builtin_future_candidate(self, goal)
+        } else if lang_items.gen_trait() == Some(trait_def_id) {
+            G::consider_builtin_generator_candidate(self, goal)
         } else {
             Err(NoSolution)
         };
@@ -314,9 +335,10 @@ fn assemble_alias_bound_candidates<G: GoalKind<'tcx>>(
             | ty::Tuple(_)
             | ty::Param(_)
             | ty::Placeholder(..)
-            | ty::Infer(_)
+            | ty::Infer(ty::IntVar(_) | ty::FloatVar(_))
             | ty::Error(_) => return,
-            ty::Bound(..) => bug!("unexpected bound type: {goal:?}"),
+            ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_))
+            | ty::Bound(..) => bug!("unexpected self type for `{goal:?}`"),
             ty::Alias(_, alias_ty) => alias_ty,
         };
 
@@ -364,9 +386,10 @@ fn assemble_object_bound_candidates<G: GoalKind<'tcx>>(
             | ty::Tuple(_)
             | ty::Param(_)
             | ty::Placeholder(..)
-            | ty::Infer(_)
+            | ty::Infer(ty::IntVar(_) | ty::FloatVar(_))
             | ty::Error(_) => return,
-            ty::Bound(..) => bug!("unexpected bound type: {goal:?}"),
+            ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_))
+            | ty::Bound(..) => bug!("unexpected self type for `{goal:?}`"),
             ty::Dynamic(bounds, ..) => bounds,
         };
 
index 40b9bedc84fd3afd8292c2c721bee97d1d8b62de..278024b22760a754a8634d5cd16b58f583948da6 100644 (file)
@@ -1,14 +1,14 @@
 use std::mem;
 
-use rustc_infer::{
-    infer::InferCtxt,
-    traits::{
-        query::NoSolution, FulfillmentError, FulfillmentErrorCode, PredicateObligation,
-        SelectionError, TraitEngine,
-    },
+use rustc_infer::infer::InferCtxt;
+use rustc_infer::traits::{
+    query::NoSolution, FulfillmentError, FulfillmentErrorCode, MismatchedProjectionTypes,
+    PredicateObligation, SelectionError, TraitEngine,
 };
+use rustc_middle::ty;
+use rustc_middle::ty::error::{ExpectedFound, TypeError};
 
-use super::{search_graph, Certainty, EvalCtxt};
+use super::{Certainty, InferCtxtEvalExt};
 
 /// A trait engine using the new trait solver.
 ///
@@ -66,16 +66,60 @@ fn select_where_possible(&mut self, infcx: &InferCtxt<'tcx>) -> Vec<FulfillmentE
             let mut has_changed = false;
             for obligation in mem::take(&mut self.obligations) {
                 let goal = obligation.clone().into();
-                let search_graph = &mut search_graph::SearchGraph::new(infcx.tcx);
-                let mut ecx = EvalCtxt::new_outside_solver(infcx, search_graph);
-                let (changed, certainty) = match ecx.evaluate_goal(goal) {
+                let (changed, certainty) = match infcx.evaluate_root_goal(goal) {
                     Ok(result) => result,
                     Err(NoSolution) => {
                         errors.push(FulfillmentError {
                             obligation: obligation.clone(),
-                            code: FulfillmentErrorCode::CodeSelectionError(
-                                SelectionError::Unimplemented,
-                            ),
+                            code: match goal.predicate.kind().skip_binder() {
+                                ty::PredicateKind::Clause(ty::Clause::Projection(_)) => {
+                                    FulfillmentErrorCode::CodeProjectionError(
+                                        // FIXME: This could be a `Sorts` if the term is a type
+                                        MismatchedProjectionTypes { err: TypeError::Mismatch },
+                                    )
+                                }
+                                ty::PredicateKind::Subtype(pred) => {
+                                    let (a, b) = infcx.replace_bound_vars_with_placeholders(
+                                        goal.predicate.kind().rebind((pred.a, pred.b)),
+                                    );
+                                    let expected_found = ExpectedFound::new(true, a, b);
+                                    FulfillmentErrorCode::CodeSubtypeError(
+                                        expected_found,
+                                        TypeError::Sorts(expected_found),
+                                    )
+                                }
+                                ty::PredicateKind::Coerce(pred) => {
+                                    let (a, b) = infcx.replace_bound_vars_with_placeholders(
+                                        goal.predicate.kind().rebind((pred.a, pred.b)),
+                                    );
+                                    let expected_found = ExpectedFound::new(false, a, b);
+                                    FulfillmentErrorCode::CodeSubtypeError(
+                                        expected_found,
+                                        TypeError::Sorts(expected_found),
+                                    )
+                                }
+                                ty::PredicateKind::ConstEquate(a, b) => {
+                                    let (a, b) = infcx.replace_bound_vars_with_placeholders(
+                                        goal.predicate.kind().rebind((a, b)),
+                                    );
+                                    let expected_found = ExpectedFound::new(true, a, b);
+                                    FulfillmentErrorCode::CodeConstEquateError(
+                                        expected_found,
+                                        TypeError::ConstMismatch(expected_found),
+                                    )
+                                }
+                                ty::PredicateKind::Clause(_)
+                                | ty::PredicateKind::WellFormed(_)
+                                | ty::PredicateKind::ObjectSafe(_)
+                                | ty::PredicateKind::ClosureKind(_, _, _)
+                                | ty::PredicateKind::ConstEvaluatable(_)
+                                | ty::PredicateKind::TypeWellFormedFromEnv(_)
+                                | ty::PredicateKind::Ambiguous => {
+                                    FulfillmentErrorCode::CodeSelectionError(
+                                        SelectionError::Unimplemented,
+                                    )
+                                }
+                            },
                             root_obligation: obligation,
                         });
                         continue;
index da2a1a19957e128f491b8a1bbc3b3384da637581..f44648c95d742530298274dc3467dc6645e127e6 100644 (file)
@@ -152,6 +152,36 @@ fn evaluate_goal(self, goal: CanonicalGoal<'tcx>) -> QueryResult<'tcx> {
     }
 }
 
+pub trait InferCtxtEvalExt<'tcx> {
+    /// Evaluates a goal from **outside** of the trait solver.
+    ///
+    /// Using this while inside of the solver is wrong as it uses a new
+    /// search graph which would break cycle detection.
+    fn evaluate_root_goal(
+        &self,
+        goal: Goal<'tcx, ty::Predicate<'tcx>>,
+    ) -> Result<(bool, Certainty), NoSolution>;
+}
+
+impl<'tcx> InferCtxtEvalExt<'tcx> for InferCtxt<'tcx> {
+    fn evaluate_root_goal(
+        &self,
+        goal: Goal<'tcx, ty::Predicate<'tcx>>,
+    ) -> Result<(bool, Certainty), NoSolution> {
+        let mut search_graph = search_graph::SearchGraph::new(self.tcx);
+
+        let result = EvalCtxt {
+            search_graph: &mut search_graph,
+            infcx: self,
+            var_values: CanonicalVarValues::dummy(),
+        }
+        .evaluate_goal(goal);
+
+        assert!(search_graph.is_empty());
+        result
+    }
+}
+
 struct EvalCtxt<'a, 'tcx> {
     infcx: &'a InferCtxt<'tcx>,
     var_values: CanonicalVarValues<'tcx>,
@@ -164,18 +194,6 @@ fn tcx(&self) -> TyCtxt<'tcx> {
         self.infcx.tcx
     }
 
-    /// Creates a new evaluation context outside of the trait solver.
-    ///
-    /// With this solver making a canonical response doesn't make much sense.
-    /// The `search_graph` for this solver has to be completely empty.
-    fn new_outside_solver(
-        infcx: &'a InferCtxt<'tcx>,
-        search_graph: &'a mut search_graph::SearchGraph<'tcx>,
-    ) -> EvalCtxt<'a, 'tcx> {
-        assert!(search_graph.is_empty());
-        EvalCtxt { infcx, var_values: CanonicalVarValues::dummy(), search_graph }
-    }
-
     #[instrument(level = "debug", skip(tcx, search_graph), ret)]
     fn evaluate_canonical_goal(
         tcx: TyCtxt<'tcx>,
@@ -259,12 +277,15 @@ fn compute_goal(&mut self, goal: Goal<'tcx, ty::Predicate<'tcx>>) -> QueryResult
                         param_env,
                         predicate: (def_id, substs, kind),
                     }),
+                ty::PredicateKind::ObjectSafe(trait_def_id) => {
+                    self.compute_object_safe_goal(trait_def_id)
+                }
+                ty::PredicateKind::WellFormed(arg) => {
+                    self.compute_well_formed_goal(Goal { param_env, predicate: arg })
+                }
                 ty::PredicateKind::Ambiguous => self.make_canonical_response(Certainty::AMBIGUOUS),
                 // FIXME: implement these predicates :)
-                ty::PredicateKind::WellFormed(_)
-                | ty::PredicateKind::ObjectSafe(_)
-                | ty::PredicateKind::ConstEvaluatable(_)
-                | ty::PredicateKind::ConstEquate(_, _) => {
+                ty::PredicateKind::ConstEvaluatable(_) | ty::PredicateKind::ConstEquate(_, _) => {
                     self.make_canonical_response(Certainty::Yes)
                 }
                 ty::PredicateKind::TypeWellFormedFromEnv(..) => {
@@ -344,6 +365,32 @@ fn compute_closure_kind_goal(
             Err(NoSolution)
         }
     }
+
+    fn compute_object_safe_goal(&mut self, trait_def_id: DefId) -> QueryResult<'tcx> {
+        if self.tcx().is_object_safe(trait_def_id) {
+            self.make_canonical_response(Certainty::Yes)
+        } else {
+            Err(NoSolution)
+        }
+    }
+
+    fn compute_well_formed_goal(
+        &mut self,
+        goal: Goal<'tcx, ty::GenericArg<'tcx>>,
+    ) -> QueryResult<'tcx> {
+        self.infcx.probe(|_| {
+            match crate::traits::wf::unnormalized_obligations(
+                self.infcx,
+                goal.param_env,
+                goal.predicate,
+            ) {
+                Some(obligations) => self.evaluate_all_and_make_canonical_response(
+                    obligations.into_iter().map(|o| o.into()).collect(),
+                ),
+                None => self.make_canonical_response(Certainty::AMBIGUOUS),
+            }
+        })
+    }
 }
 
 impl<'tcx> EvalCtxt<'_, 'tcx> {
index 32e15f03998b3598431b58e417d87938e5cab02d..b583705ac43693a6619c1776ce1df2efe37bea02 100644 (file)
@@ -7,6 +7,7 @@
 use rustc_errors::ErrorGuaranteed;
 use rustc_hir::def::DefKind;
 use rustc_hir::def_id::DefId;
+use rustc_hir::LangItem;
 use rustc_infer::infer::InferCtxt;
 use rustc_infer::traits::query::NoSolution;
 use rustc_infer::traits::specialization_graph::LeafDef;
@@ -15,7 +16,7 @@
 use rustc_middle::ty::{self, Ty, TyCtxt};
 use rustc_middle::ty::{ProjectionPredicate, TypeSuperVisitable, TypeVisitor};
 use rustc_middle::ty::{ToPredicate, TypeVisitable};
-use rustc_span::DUMMY_SP;
+use rustc_span::{sym, DUMMY_SP};
 use std::iter;
 use std::ops::ControlFlow;
 
@@ -391,6 +392,165 @@ fn consider_builtin_tuple_candidate(
     ) -> QueryResult<'tcx> {
         bug!("`Tuple` does not have an associated type: {:?}", goal);
     }
+
+    fn consider_builtin_pointee_candidate(
+        ecx: &mut EvalCtxt<'_, 'tcx>,
+        goal: Goal<'tcx, Self>,
+    ) -> QueryResult<'tcx> {
+        let tcx = ecx.tcx();
+        ecx.infcx.probe(|_| {
+            let metadata_ty = match goal.predicate.self_ty().kind() {
+                ty::Bool
+                | ty::Char
+                | ty::Int(..)
+                | ty::Uint(..)
+                | ty::Float(..)
+                | ty::Array(..)
+                | ty::RawPtr(..)
+                | ty::Ref(..)
+                | ty::FnDef(..)
+                | ty::FnPtr(..)
+                | ty::Closure(..)
+                | ty::Infer(ty::IntVar(..) | ty::FloatVar(..))
+                | ty::Generator(..)
+                | ty::GeneratorWitness(..)
+                | ty::Never
+                | ty::Foreign(..) => tcx.types.unit,
+
+                ty::Error(e) => tcx.ty_error_with_guaranteed(*e),
+
+                ty::Str | ty::Slice(_) => tcx.types.usize,
+
+                ty::Dynamic(_, _, _) => {
+                    let dyn_metadata = tcx.require_lang_item(LangItem::DynMetadata, None);
+                    tcx.bound_type_of(dyn_metadata)
+                        .subst(tcx, &[ty::GenericArg::from(goal.predicate.self_ty())])
+                }
+
+                ty::Alias(_, _) | ty::Param(_) | ty::Placeholder(..) => {
+                    // FIXME(ptr_metadata): It would also be possible to return a `Ok(Ambig)` with no constraints.
+                    let sized_predicate = ty::Binder::dummy(tcx.at(DUMMY_SP).mk_trait_ref(
+                        LangItem::Sized,
+                        [ty::GenericArg::from(goal.predicate.self_ty())],
+                    ));
+
+                    let mut nested_goals = ecx.infcx.eq(
+                        goal.param_env,
+                        goal.predicate.term.ty().unwrap(),
+                        tcx.types.unit,
+                    )?;
+                    nested_goals.push(goal.with(tcx, sized_predicate));
+
+                    return ecx.evaluate_all_and_make_canonical_response(nested_goals);
+                }
+
+                ty::Adt(def, substs) if def.is_struct() => {
+                    match def.non_enum_variant().fields.last() {
+                        None => tcx.types.unit,
+                        Some(field_def) => {
+                            let self_ty = field_def.ty(tcx, substs);
+                            let new_goal = goal.with(
+                                tcx,
+                                ty::Binder::dummy(goal.predicate.with_self_ty(tcx, self_ty)),
+                            );
+                            return ecx.evaluate_all_and_make_canonical_response(vec![new_goal]);
+                        }
+                    }
+                }
+                ty::Adt(_, _) => tcx.types.unit,
+
+                ty::Tuple(elements) => match elements.last() {
+                    None => tcx.types.unit,
+                    Some(&self_ty) => {
+                        let new_goal = goal.with(
+                            tcx,
+                            ty::Binder::dummy(goal.predicate.with_self_ty(tcx, self_ty)),
+                        );
+                        return ecx.evaluate_all_and_make_canonical_response(vec![new_goal]);
+                    }
+                },
+
+                ty::Infer(
+                    ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_),
+                )
+                | ty::Bound(..) => bug!(
+                    "unexpected self ty `{:?}` when normalizing `<T as Pointee>::Metadata`",
+                    goal.predicate.self_ty()
+                ),
+            };
+
+            let nested_goals =
+                ecx.infcx.eq(goal.param_env, goal.predicate.term.ty().unwrap(), metadata_ty)?;
+            ecx.evaluate_all_and_make_canonical_response(nested_goals)
+        })
+    }
+
+    fn consider_builtin_future_candidate(
+        ecx: &mut EvalCtxt<'_, 'tcx>,
+        goal: Goal<'tcx, Self>,
+    ) -> QueryResult<'tcx> {
+        let self_ty = goal.predicate.self_ty();
+        let ty::Generator(def_id, substs, _) = *self_ty.kind() else {
+            return Err(NoSolution);
+        };
+
+        // Generators are not futures unless they come from `async` desugaring
+        let tcx = ecx.tcx();
+        if !tcx.generator_is_async(def_id) {
+            return Err(NoSolution);
+        }
+
+        let term = substs.as_generator().return_ty().into();
+
+        Self::consider_assumption(
+            ecx,
+            goal,
+            ty::Binder::dummy(ty::ProjectionPredicate {
+                projection_ty: ecx.tcx().mk_alias_ty(goal.predicate.def_id(), [self_ty]),
+                term,
+            })
+            .to_predicate(tcx),
+        )
+    }
+
+    fn consider_builtin_generator_candidate(
+        ecx: &mut EvalCtxt<'_, 'tcx>,
+        goal: Goal<'tcx, Self>,
+    ) -> QueryResult<'tcx> {
+        let self_ty = goal.predicate.self_ty();
+        let ty::Generator(def_id, substs, _) = *self_ty.kind() else {
+            return Err(NoSolution);
+        };
+
+        // `async`-desugared generators do not implement the generator trait
+        let tcx = ecx.tcx();
+        if tcx.generator_is_async(def_id) {
+            return Err(NoSolution);
+        }
+
+        let generator = substs.as_generator();
+
+        let name = tcx.associated_item(goal.predicate.def_id()).name;
+        let term = if name == sym::Return {
+            generator.return_ty().into()
+        } else if name == sym::Yield {
+            generator.yield_ty().into()
+        } else {
+            bug!("unexpected associated item `<{self_ty} as Generator>::{name}`")
+        };
+
+        Self::consider_assumption(
+            ecx,
+            goal,
+            ty::Binder::dummy(ty::ProjectionPredicate {
+                projection_ty: ecx
+                    .tcx()
+                    .mk_alias_ty(goal.predicate.def_id(), [self_ty, generator.resume_ty()]),
+                term,
+            })
+            .to_predicate(tcx),
+        )
+    }
 }
 
 /// This behavior is also implemented in `rustc_ty_utils` and in the old `project` code.
index 4b6d673c999c96fd7dab198e99a3aec327ceba70..d74857dc4b4803bac6b418941d6e9122dd1fae3b 100644 (file)
@@ -185,6 +185,57 @@ fn consider_builtin_tuple_candidate(
             Err(NoSolution)
         }
     }
+
+    fn consider_builtin_pointee_candidate(
+        ecx: &mut EvalCtxt<'_, 'tcx>,
+        _goal: Goal<'tcx, Self>,
+    ) -> QueryResult<'tcx> {
+        ecx.make_canonical_response(Certainty::Yes)
+    }
+
+    fn consider_builtin_future_candidate(
+        ecx: &mut EvalCtxt<'_, 'tcx>,
+        goal: Goal<'tcx, Self>,
+    ) -> QueryResult<'tcx> {
+        let ty::Generator(def_id, _, _) = *goal.predicate.self_ty().kind() else {
+            return Err(NoSolution);
+        };
+
+        // Generators are not futures unless they come from `async` desugaring
+        let tcx = ecx.tcx();
+        if !tcx.generator_is_async(def_id) {
+            return Err(NoSolution);
+        }
+
+        // Async generator unconditionally implement `Future`
+        ecx.make_canonical_response(Certainty::Yes)
+    }
+
+    fn consider_builtin_generator_candidate(
+        ecx: &mut EvalCtxt<'_, 'tcx>,
+        goal: Goal<'tcx, Self>,
+    ) -> QueryResult<'tcx> {
+        let self_ty = goal.predicate.self_ty();
+        let ty::Generator(def_id, substs, _) = *self_ty.kind() else {
+            return Err(NoSolution);
+        };
+
+        // `async`-desugared generators do not implement the generator trait
+        let tcx = ecx.tcx();
+        if tcx.generator_is_async(def_id) {
+            return Err(NoSolution);
+        }
+
+        let generator = substs.as_generator();
+        Self::consider_assumption(
+            ecx,
+            goal,
+            ty::Binder::dummy(
+                tcx.mk_trait_ref(goal.predicate.def_id(), [self_ty, generator.resume_ty()]),
+            )
+            .to_predicate(tcx),
+        )
+    }
 }
 
 impl<'tcx> EvalCtxt<'_, 'tcx> {
index a11cd13cb0856b4df3ace3c1261baf9a69d9d4dc..c2a19372f18c4f97e352ec7d426820fc2901752c 100644 (file)
@@ -24,15 +24,16 @@ pub(super) fn instantiate_constituent_tys_for_auto_trait<'tcx>(
         | ty::Never
         | ty::Char => Ok(vec![]),
 
-        ty::Placeholder(..)
-        | ty::Dynamic(..)
+        ty::Dynamic(..)
         | ty::Param(..)
         | ty::Foreign(..)
         | ty::Alias(ty::Projection, ..)
-        | ty::Bound(..)
-        | ty::Infer(ty::TyVar(_)) => Err(NoSolution),
+        | ty::Placeholder(..) => Err(NoSolution),
 
-        ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => bug!(),
+        ty::Bound(..)
+        | ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => {
+            bug!("unexpected type `{ty}`")
+        }
 
         ty::RawPtr(ty::TypeAndMut { ty: element_ty, .. }) | ty::Ref(_, element_ty, _) => {
             Ok(vec![element_ty])
@@ -99,11 +100,12 @@ pub(super) fn instantiate_constituent_tys_for_sized_trait<'tcx>(
         | ty::Foreign(..)
         | ty::Alias(..)
         | ty::Param(_)
-        | ty::Infer(ty::TyVar(_)) => Err(NoSolution),
+        | ty::Placeholder(..) => Err(NoSolution),
 
-        ty::Placeholder(..)
-        | ty::Bound(..)
-        | ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => bug!(),
+        ty::Bound(..)
+        | ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => {
+            bug!("unexpected type `{ty}`")
+        }
 
         ty::Tuple(tys) => Ok(tys.to_vec()),
 
@@ -148,11 +150,12 @@ pub(super) fn instantiate_constituent_tys_for_copy_clone_trait<'tcx>(
         | ty::Adt(_, _)
         | ty::Alias(_, _)
         | ty::Param(_)
-        | ty::Infer(ty::TyVar(_)) => Err(NoSolution),
+        | ty::Placeholder(..) => Err(NoSolution),
 
-        ty::Placeholder(..)
-        | ty::Bound(..)
-        | ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => bug!(),
+        ty::Bound(..)
+        | ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => {
+            bug!("unexpected type `{ty}`")
+        }
 
         ty::Tuple(tys) => Ok(tys.to_vec()),
 
@@ -173,6 +176,7 @@ pub(super) fn instantiate_constituent_tys_for_copy_clone_trait<'tcx>(
     }
 }
 
+// Returns a binder of the tupled inputs types and output type from a builtin callable type.
 pub(crate) fn extract_tupled_inputs_and_output_from_callable<'tcx>(
     tcx: TyCtxt<'tcx>,
     self_ty: Ty<'tcx>,
@@ -215,9 +219,13 @@ pub(crate) fn extract_tupled_inputs_and_output_from_callable<'tcx>(
         | ty::Tuple(_)
         | ty::Alias(_, _)
         | ty::Param(_)
-        | ty::Placeholder(_)
-        | ty::Bound(_, _)
-        | ty::Infer(_)
+        | ty::Placeholder(..)
+        | ty::Infer(ty::IntVar(_) | ty::FloatVar(_))
         | ty::Error(_) => Err(NoSolution),
+
+        ty::Bound(..)
+        | ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => {
+            bug!("unexpected type `{self_ty}`")
+        }
     }
 }
index 225c1050c7c952fc41230b7bdde07365d65ad419..ecee0bf7a6d1b7aa422d95b16e32eb8aed946901 100644 (file)
@@ -17,7 +17,6 @@
 use rustc_data_structures::fx::FxIndexSet;
 use rustc_errors::Diagnostic;
 use rustc_hir::def_id::{DefId, CRATE_DEF_ID, LOCAL_CRATE};
-use rustc_hir::CRATE_HIR_ID;
 use rustc_infer::infer::{DefiningAnchor, InferCtxt, TyCtxtInferExt};
 use rustc_infer::traits::util;
 use rustc_middle::traits::specialization_graph::OverlapMode;
@@ -382,18 +381,14 @@ fn resolve_negative_obligation<'tcx>(
         return false;
     }
 
-    let (body_id, body_def_id) = if let Some(body_def_id) = body_def_id.as_local() {
-        (tcx.hir().local_def_id_to_hir_id(body_def_id), body_def_id)
-    } else {
-        (CRATE_HIR_ID, CRATE_DEF_ID)
-    };
+    let body_def_id = body_def_id.as_local().unwrap_or(CRATE_DEF_ID);
 
     let ocx = ObligationCtxt::new(&infcx);
     let wf_tys = ocx.assumed_wf_types(param_env, DUMMY_SP, body_def_id);
     let outlives_env = OutlivesEnvironment::with_bounds(
         param_env,
         Some(&infcx),
-        infcx.implied_bounds_tys(param_env, body_id, wf_tys),
+        infcx.implied_bounds_tys(param_env, body_def_id, wf_tys),
     );
 
     infcx.process_registered_region_obligations(outlives_env.region_bound_pairs(), param_env);
index 369f80139a806c7fb00b02de7a8caf8fd4cd0919..a2ddd91546c18814f8bdce17c2b8647698b9aeee 100644 (file)
@@ -190,8 +190,7 @@ pub fn assumed_wf_types(
         let tcx = self.infcx.tcx;
         let assumed_wf_types = tcx.assumed_wf_types(def_id);
         let mut implied_bounds = FxIndexSet::default();
-        let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
-        let cause = ObligationCause::misc(span, hir_id);
+        let cause = ObligationCause::misc(span, def_id);
         for ty in assumed_wf_types {
             // FIXME(@lcnr): rustc currently does not check wf for types
             // pre-normalization, meaning that implied bounds are sometimes
index 0419bb3f724f9ed86454dc73c60dc5db20502ada..6bf453c3ff084376b2afa27c74384acbf4e5a8bd 100644 (file)
@@ -81,7 +81,7 @@ pub fn recompute_applicable_impls<'tcx>(
     );
 
     let predicates =
-        tcx.predicates_of(obligation.cause.body_id.owner.to_def_id()).instantiate_identity(tcx);
+        tcx.predicates_of(obligation.cause.body_id.to_def_id()).instantiate_identity(tcx);
     for obligation in elaborate_predicates_with_span(tcx, predicates.into_iter()) {
         let kind = obligation.predicate.kind();
         if let ty::PredicateKind::Clause(ty::Clause::Trait(trait_pred)) = kind.skip_binder()
index 52971486c553e361fe1d91cf55947ca15de59b45..98917430d241d46e96ba0af666ca78f4b8cca62b 100644 (file)
@@ -839,14 +839,7 @@ fn report_selection_error(
                             err.note(s.as_str());
                         }
                         if let Some(ref s) = parent_label {
-                            let body = tcx
-                                .hir()
-                                .opt_local_def_id(obligation.cause.body_id)
-                                .unwrap_or_else(|| {
-                                    tcx.hir().body_owner_def_id(hir::BodyId {
-                                        hir_id: obligation.cause.body_id,
-                                    })
-                                });
+                            let body = obligation.cause.body_id;
                             err.span_label(tcx.def_span(body), s);
                         }
 
@@ -934,6 +927,8 @@ fn report_selection_error(
                             );
                         }
 
+                        let body_hir_id =
+                            self.tcx.hir().local_def_id_to_hir_id(obligation.cause.body_id);
                         // Try to report a help message
                         if is_fn_trait
                             && let Ok((implemented_kind, params)) = self.type_implements_fn_trait(
@@ -1014,7 +1009,7 @@ fn report_selection_error(
                             if !self.report_similar_impl_candidates(
                                 impl_candidates,
                                 trait_ref,
-                                obligation.cause.body_id,
+                                body_hir_id,
                                 &mut err,
                                 true,
                             ) {
@@ -1050,7 +1045,7 @@ fn report_selection_error(
                                     self.report_similar_impl_candidates(
                                         impl_candidates,
                                         trait_ref,
-                                        obligation.cause.body_id,
+                                        body_hir_id,
                                         &mut err,
                                         true,
                                     );
@@ -2305,10 +2300,12 @@ fn maybe_report_ambiguity(
                                 predicate.to_opt_poly_trait_pred().unwrap(),
                             );
                             if impl_candidates.len() < 10 {
+                                let hir =
+                                    self.tcx.hir().local_def_id_to_hir_id(obligation.cause.body_id);
                                 self.report_similar_impl_candidates(
                                     impl_candidates,
                                     trait_ref,
-                                    body_id.map(|id| id.hir_id).unwrap_or(obligation.cause.body_id),
+                                    body_id.map(|id| id.hir_id).unwrap_or(hir),
                                     &mut err,
                                     false,
                                 );
@@ -2828,7 +2825,7 @@ pub struct FindExprBySpan<'hir> {
 }
 
 impl<'hir> FindExprBySpan<'hir> {
-    fn new(span: Span) -> Self {
+    pub fn new(span: Span) -> Self {
         Self { span, result: None, ty_result: None }
     }
 }
index 18d308f7123aec90bf1d9192e1cc5b24b76dc8a8..a3209d35e58be577186af66ae55e9ccde446603e 100644 (file)
@@ -149,10 +149,9 @@ fn on_unimplemented_note(
             .unwrap_or_else(|| (trait_ref.def_id(), trait_ref.skip_binder().substs));
         let trait_ref = trait_ref.skip_binder();
 
-        let mut flags = vec![(
-            sym::ItemContext,
-            self.describe_enclosure(obligation.cause.body_id).map(|s| s.to_owned()),
-        )];
+        let body_hir = self.tcx.hir().local_def_id_to_hir_id(obligation.cause.body_id);
+        let mut flags =
+            vec![(sym::ItemContext, self.describe_enclosure(body_hir).map(|s| s.to_owned()))];
 
         match obligation.cause.code() {
             ObligationCauseCode::BuiltinDerivedObligation(..)
index 39e50b2accf17af05b1f4acb4f0c8d2451267e81..bf5e77e6ce12fe4298f16970dd10ed4a41a2e4c4 100644 (file)
@@ -9,7 +9,6 @@
 use crate::traits::{NormalizeExt, ObligationCtxt};
 
 use hir::def::CtorOf;
-use hir::{Expr, HirId};
 use rustc_data_structures::fx::FxHashSet;
 use rustc_data_structures::stack::ensure_sufficient_stack;
 use rustc_errors::{
@@ -22,6 +21,7 @@
 use rustc_hir::intravisit::Visitor;
 use rustc_hir::lang_items::LangItem;
 use rustc_hir::{AsyncGeneratorKind, GeneratorKind, Node};
+use rustc_hir::{Expr, HirId};
 use rustc_infer::infer::error_reporting::TypeErrCtxt;
 use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
 use rustc_infer::infer::{InferOk, LateBoundRegionConversionTime};
@@ -34,6 +34,7 @@
     IsSuggestable, ToPredicate, Ty, TyCtxt, TypeAndMut, TypeFoldable, TypeFolder,
     TypeSuperFoldable, TypeVisitable, TypeckResults,
 };
+use rustc_span::def_id::LocalDefId;
 use rustc_span::symbol::{sym, Ident, Symbol};
 use rustc_span::{BytePos, DesugaringKind, ExpnKind, MacroKind, Span, DUMMY_SP};
 use rustc_target::spec::abi;
@@ -179,7 +180,7 @@ fn suggest_restricting_param_bound(
         err: &mut Diagnostic,
         trait_pred: ty::PolyTraitPredicate<'tcx>,
         associated_item: Option<(&'static str, Ty<'tcx>)>,
-        body_id: hir::HirId,
+        body_id: LocalDefId,
     );
 
     fn suggest_dereferences(
@@ -522,7 +523,7 @@ fn suggest_restricting_param_bound(
         mut err: &mut Diagnostic,
         trait_pred: ty::PolyTraitPredicate<'tcx>,
         associated_ty: Option<(&'static str, Ty<'tcx>)>,
-        body_id: hir::HirId,
+        body_id: LocalDefId,
     ) {
         let trait_pred = self.resolve_numeric_literals_with_default(trait_pred);
 
@@ -535,8 +536,9 @@ fn suggest_restricting_param_bound(
 
         // FIXME: Add check for trait bound that is already present, particularly `?Sized` so we
         //        don't suggest `T: Sized + ?Sized`.
-        let mut hir_id = body_id;
-        while let Some(node) = self.tcx.hir().find(hir_id) {
+        let mut body_id = body_id;
+        while let Some(node) = self.tcx.hir().find_by_def_id(body_id) {
+            let hir_id = self.tcx.hir().local_def_id_to_hir_id(body_id);
             match node {
                 hir::Node::Item(hir::Item {
                     ident,
@@ -713,8 +715,7 @@ fn suggest_restricting_param_bound(
 
                 _ => {}
             }
-
-            hir_id = self.tcx.hir().get_parent_item(hir_id).into();
+            body_id = self.tcx.local_parent(body_id);
         }
     }
 
@@ -905,8 +906,9 @@ fn suggest_fn_call(
             trait_pred.self_ty(),
         );
 
+        let body_hir_id = self.tcx.hir().local_def_id_to_hir_id(obligation.cause.body_id);
         let Some((def_id_or_name, output, inputs)) = self.extract_callable_info(
-            obligation.cause.body_id,
+            body_hir_id,
             obligation.param_env,
             self_ty,
         ) else { return false; };
@@ -1004,8 +1006,9 @@ fn check_for_binding_assigned_block_without_tail_expression(
             span.remove_mark();
         }
         let mut expr_finder = FindExprBySpan::new(span);
-        let Some(hir::Node::Expr(body)) = self.tcx.hir().find(obligation.cause.body_id) else { return; };
-        expr_finder.visit_expr(&body);
+        let Some(body_id) = self.tcx.hir().maybe_body_owned_by(obligation.cause.body_id) else { return; };
+        let body = self.tcx.hir().body(body_id);
+        expr_finder.visit_expr(body.value);
         let Some(expr) = expr_finder.result else { return; };
         let Some(typeck) = &self.typeck_results else { return; };
         let Some(ty) = typeck.expr_ty_adjusted_opt(expr) else { return; };
@@ -1060,8 +1063,7 @@ fn suggest_add_clone_to_arg(
     ) -> bool {
         let self_ty = self.resolve_vars_if_possible(trait_pred.self_ty());
         let ty = self.tcx.erase_late_bound_regions(self_ty);
-        let owner = self.tcx.hir().get_parent_item(obligation.cause.body_id);
-        let Some(generics) = self.tcx.hir().get_generics(owner.def_id) else { return false };
+        let Some(generics) = self.tcx.hir().get_generics(obligation.cause.body_id) else { return false };
         let ty::Ref(_, inner_ty, hir::Mutability::Not) = ty.kind() else { return false };
         let ty::Param(param) = inner_ty.kind() else { return false };
         let ObligationCauseCode::FunctionArgumentObligation { arg_hir_id, .. } = obligation.cause.code() else { return false };
@@ -1104,6 +1106,7 @@ fn suggest_add_clone_to_arg(
     /// Extracts information about a callable type for diagnostics. This is a
     /// heuristic -- it doesn't necessarily mean that a type is always callable,
     /// because the callable type must also be well-formed to be called.
+    // FIXME(vincenzopalazzo): move the HirId to a LocalDefId
     fn extract_callable_info(
         &self,
         hir_id: HirId,
@@ -1429,10 +1432,11 @@ fn suggest_remove_reference(
             span.remove_mark();
         }
         let mut expr_finder = super::FindExprBySpan::new(span);
-        let Some(hir::Node::Expr(body)) = self.tcx.hir().find(obligation.cause.body_id) else {
+        let Some(body_id) = self.tcx.hir().maybe_body_owned_by(obligation.cause.body_id) else {
             return false;
         };
-        expr_finder.visit_expr(&body);
+        let body = self.tcx.hir().body(body_id);
+        expr_finder.visit_expr(body.value);
         let mut maybe_suggest = |suggested_ty, count, suggestions| {
             // Remapping bound vars here
             let trait_pred_and_suggested_ty =
@@ -1670,8 +1674,7 @@ fn suggest_semicolon_removal(
         trait_pred: ty::PolyTraitPredicate<'tcx>,
     ) -> bool {
         let hir = self.tcx.hir();
-        let parent_node = hir.parent_id(obligation.cause.body_id);
-        let node = hir.find(parent_node);
+        let node = hir.find_by_def_id(obligation.cause.body_id);
         if let Some(hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(sig, _, body_id), .. })) = node
             && let hir::ExprKind::Block(blk, _) = &hir.body(*body_id).value.kind
             && sig.decl.output.span().overlaps(span)
@@ -1707,8 +1710,7 @@ fn suggest_semicolon_removal(
 
     fn return_type_span(&self, obligation: &PredicateObligation<'tcx>) -> Option<Span> {
         let hir = self.tcx.hir();
-        let parent_node = hir.parent_id(obligation.cause.body_id);
-        let Some(hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(sig, ..), .. })) = hir.find(parent_node) else {
+        let Some(hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(sig, ..), .. })) = hir.find_by_def_id(obligation.cause.body_id) else {
             return None;
         };
 
@@ -1732,8 +1734,8 @@ fn suggest_impl_trait(
         }
 
         let hir = self.tcx.hir();
-        let fn_hir_id = hir.parent_id(obligation.cause.body_id);
-        let node = hir.find(fn_hir_id);
+        let fn_hir_id = hir.local_def_id_to_hir_id(obligation.cause.body_id);
+        let node = hir.find_by_def_id(obligation.cause.body_id);
         let Some(hir::Node::Item(hir::Item {
             kind: hir::ItemKind::Fn(sig, _, body_id),
             ..
@@ -1806,7 +1808,7 @@ fn suggest_impl_trait(
 
         match liberated_sig.output().kind() {
             ty::Dynamic(predicates, _, ty::Dyn) => {
-                let cause = ObligationCause::misc(ret_ty.span, fn_hir_id);
+                let cause = ObligationCause::misc(ret_ty.span, obligation.cause.body_id);
                 let param_env = ty::ParamEnv::empty();
 
                 if !only_never_return {
@@ -1944,8 +1946,7 @@ fn point_at_returns_when_relevant(
         }
 
         let hir = self.tcx.hir();
-        let parent_node = hir.parent_id(obligation.cause.body_id);
-        let node = hir.find(parent_node);
+        let node = hir.find_by_def_id(obligation.cause.body_id);
         if let Some(hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(_, _, body_id), .. })) =
             node
         {
@@ -3283,12 +3284,7 @@ fn suggest_await_before_try(
         trait_pred: ty::PolyTraitPredicate<'tcx>,
         span: Span,
     ) {
-        let body_hir_id = obligation.cause.body_id;
-        let item_id = self.tcx.hir().parent_id(body_hir_id);
-
-        if let Some(body_id) =
-            self.tcx.hir().maybe_body_owned_by(self.tcx.hir().local_def_id(item_id))
-        {
+        if let Some(body_id) = self.tcx.hir().maybe_body_owned_by(obligation.cause.body_id) {
             let body = self.tcx.hir().body(body_id);
             if let Some(hir::GeneratorKind::Async(_)) = body.generator_kind {
                 let future_trait = self.tcx.require_lang_item(LangItem::Future, None);
@@ -3727,9 +3723,14 @@ fn probe_assoc_types_at_expr(
                     term: ty_var.into(),
                 },
             )));
+            let body_def_id = self.tcx.hir().enclosing_body_owner(body_id);
             // Add `<ExprTy as Iterator>::Item = _` obligation.
             ocx.register_obligation(Obligation::misc(
-                self.tcx, span, body_id, param_env, projection,
+                self.tcx,
+                span,
+                body_def_id,
+                param_env,
+                projection,
             ));
             if ocx.select_where_possible().is_empty() {
                 // `ty_var` now holds the type that `Item` is for `ExprTy`.
index 3c640cdc503ceba9010ffe62f5119be36868ff2f..83458017e00f00b7cabdc6871aedbdf492d0f130 100644 (file)
 use crate::traits::error_reporting::TypeErrCtxtExt as _;
 use crate::traits::query::evaluate_obligation::InferCtxtExt as _;
 use rustc_errors::ErrorGuaranteed;
-use rustc_hir as hir;
-use rustc_hir::def_id::DefId;
 use rustc_middle::ty::fold::TypeFoldable;
 use rustc_middle::ty::visit::TypeVisitable;
 use rustc_middle::ty::{self, DefIdTree, ToPredicate, Ty, TyCtxt, TypeSuperVisitable};
 use rustc_middle::ty::{InternalSubsts, SubstsRef};
+use rustc_span::def_id::{DefId, CRATE_DEF_ID};
 use rustc_span::Span;
 
 use std::fmt::Debug;
@@ -151,7 +150,7 @@ fn pred_known_to_hold_modulo_regions<'tcx>(
         // We can use a dummy node-id here because we won't pay any mind
         // to region obligations that arise (there shouldn't really be any
         // anyhow).
-        cause: ObligationCause::misc(span, hir::CRATE_HIR_ID),
+        cause: ObligationCause::misc(span, CRATE_DEF_ID),
         recursion_depth: 0,
         predicate: pred.to_predicate(infcx.tcx),
     };
@@ -166,14 +165,12 @@ fn pred_known_to_hold_modulo_regions<'tcx>(
         // that guess. While imperfect, I believe this is sound.
 
         // FIXME(@lcnr): this function doesn't seem right.
+        //
         // The handling of regions in this area of the code is terrible,
         // see issue #29149. We should be able to improve on this with
         // NLL.
         let errors = fully_solve_obligation(infcx, obligation);
 
-        // Note: we only assume something is `Copy` if we can
-        // *definitively* show that it implements `Copy`. Otherwise,
-        // assume it is move; linear is always ok.
         match &errors[..] {
             [] => true,
             errors => {
index f2c5f730b31b938ed858a46156458f02d3717496..6cb64ad574f5be191db9341065d1245b3b306c16 100644 (file)
@@ -3,9 +3,8 @@
 use crate::traits::query::NoSolution;
 use crate::traits::ObligationCause;
 use rustc_data_structures::fx::FxIndexSet;
-use rustc_hir as hir;
-use rustc_hir::HirId;
 use rustc_middle::ty::{self, ParamEnv, Ty};
+use rustc_span::def_id::LocalDefId;
 
 pub use rustc_middle::traits::query::OutlivesBound;
 
@@ -14,14 +13,14 @@ pub trait InferCtxtExt<'a, 'tcx> {
     fn implied_outlives_bounds(
         &self,
         param_env: ty::ParamEnv<'tcx>,
-        body_id: hir::HirId,
+        body_id: LocalDefId,
         ty: Ty<'tcx>,
     ) -> Vec<OutlivesBound<'tcx>>;
 
     fn implied_bounds_tys(
         &'a self,
         param_env: ty::ParamEnv<'tcx>,
-        body_id: hir::HirId,
+        body_id: LocalDefId,
         tys: FxIndexSet<Ty<'tcx>>,
     ) -> Bounds<'a, 'tcx>;
 }
@@ -50,10 +49,10 @@ impl<'a, 'tcx: 'a> InferCtxtExt<'a, 'tcx> for InferCtxt<'tcx> {
     fn implied_outlives_bounds(
         &self,
         param_env: ty::ParamEnv<'tcx>,
-        body_id: hir::HirId,
+        body_id: LocalDefId,
         ty: Ty<'tcx>,
     ) -> Vec<OutlivesBound<'tcx>> {
-        let span = self.tcx.hir().span(body_id);
+        let span = self.tcx.def_span(body_id);
         let result = param_env
             .and(type_op::implied_outlives_bounds::ImpliedOutlivesBounds { ty })
             .fully_perform(self);
@@ -102,7 +101,7 @@ fn implied_outlives_bounds(
     fn implied_bounds_tys(
         &'a self,
         param_env: ParamEnv<'tcx>,
-        body_id: HirId,
+        body_id: LocalDefId,
         tys: FxIndexSet<Ty<'tcx>>,
     ) -> Bounds<'a, 'tcx> {
         tys.into_iter()
index 12d4cb4fc6920a0d07438637415bff6980d058cb..767e31ddf781a9666bde067a1162e10ada3f478a 100644 (file)
@@ -1,11 +1,11 @@
 use crate::infer::InferCtxt;
 use crate::traits;
 use rustc_hir as hir;
-use rustc_hir::def_id::DefId;
 use rustc_hir::lang_items::LangItem;
 use rustc_middle::ty::subst::{GenericArg, GenericArgKind, SubstsRef};
 use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitable};
-use rustc_span::Span;
+use rustc_span::def_id::{DefId, LocalDefId, CRATE_DEF_ID};
+use rustc_span::{Span, DUMMY_SP};
 
 use std::iter;
 /// Returns the set of obligations needed to make `arg` well-formed.
@@ -17,7 +17,7 @@
 pub fn obligations<'tcx>(
     infcx: &InferCtxt<'tcx>,
     param_env: ty::ParamEnv<'tcx>,
-    body_id: hir::HirId,
+    body_id: LocalDefId,
     recursion_depth: usize,
     arg: GenericArg<'tcx>,
     span: Span,
@@ -75,6 +75,34 @@ pub fn obligations<'tcx>(
     Some(result)
 }
 
+/// Compute the predicates that are required for a type to be well-formed.
+///
+/// This is only intended to be used in the new solver, since it does not
+/// take into account recursion depth or proper error-reporting spans.
+pub fn unnormalized_obligations<'tcx>(
+    infcx: &InferCtxt<'tcx>,
+    param_env: ty::ParamEnv<'tcx>,
+    arg: GenericArg<'tcx>,
+) -> Option<Vec<traits::PredicateObligation<'tcx>>> {
+    if let ty::GenericArgKind::Lifetime(..) = arg.unpack() {
+        return Some(vec![]);
+    }
+
+    debug_assert_eq!(arg, infcx.resolve_vars_if_possible(arg));
+
+    let mut wf = WfPredicates {
+        tcx: infcx.tcx,
+        param_env,
+        body_id: CRATE_DEF_ID,
+        span: DUMMY_SP,
+        out: vec![],
+        recursion_depth: 0,
+        item: None,
+    };
+    wf.compute(arg);
+    Some(wf.out)
+}
+
 /// Returns the obligations that make this trait reference
 /// well-formed. For example, if there is a trait `Set` defined like
 /// `trait Set<K:Eq>`, then the trait reference `Foo: Set<Bar>` is WF
@@ -82,7 +110,7 @@ pub fn obligations<'tcx>(
 pub fn trait_obligations<'tcx>(
     infcx: &InferCtxt<'tcx>,
     param_env: ty::ParamEnv<'tcx>,
-    body_id: hir::HirId,
+    body_id: LocalDefId,
     trait_pred: &ty::TraitPredicate<'tcx>,
     span: Span,
     item: &'tcx hir::Item<'tcx>,
@@ -105,7 +133,7 @@ pub fn trait_obligations<'tcx>(
 pub fn predicate_obligations<'tcx>(
     infcx: &InferCtxt<'tcx>,
     param_env: ty::ParamEnv<'tcx>,
-    body_id: hir::HirId,
+    body_id: LocalDefId,
     predicate: ty::Predicate<'tcx>,
     span: Span,
 ) -> Vec<traits::PredicateObligation<'tcx>> {
@@ -167,7 +195,7 @@ pub fn predicate_obligations<'tcx>(
 struct WfPredicates<'tcx> {
     tcx: TyCtxt<'tcx>,
     param_env: ty::ParamEnv<'tcx>,
-    body_id: hir::HirId,
+    body_id: LocalDefId,
     span: Span,
     out: Vec<traits::PredicateObligation<'tcx>>,
     recursion_depth: usize,
index 7d2d8433c932d8d9d40b5656c1a78c99af9694de..fe633d687d91baff202ec6364841dbcd1888d19e 100644 (file)
@@ -2,13 +2,13 @@
 //! Do not call this query directory. See
 //! [`rustc_trait_selection::traits::query::type_op::implied_outlives_bounds`].
 
-use rustc_hir as hir;
 use rustc_infer::infer::canonical::{self, Canonical};
 use rustc_infer::infer::outlives::components::{push_outlives_components, Component};
 use rustc_infer::infer::TyCtxtInferExt;
 use rustc_infer::traits::query::OutlivesBound;
 use rustc_middle::ty::query::Providers;
 use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitable};
+use rustc_span::def_id::CRATE_DEF_ID;
 use rustc_span::source_map::DUMMY_SP;
 use rustc_trait_selection::infer::InferCtxtBuilderExt;
 use rustc_trait_selection::traits::query::{CanonicalTyGoal, Fallible, NoSolution};
@@ -67,9 +67,8 @@ fn compute_implied_outlives_bounds<'tcx>(
         // FIXME(@lcnr): It's not really "always fine", having fewer implied
         // bounds can be backward incompatible, e.g. #101951 was caused by
         // us not dealing with inference vars in `TypeOutlives` predicates.
-        let obligations =
-            wf::obligations(ocx.infcx, param_env, hir::CRATE_HIR_ID, 0, arg, DUMMY_SP)
-                .unwrap_or_default();
+        let obligations = wf::obligations(ocx.infcx, param_env, CRATE_DEF_ID, 0, arg, DUMMY_SP)
+            .unwrap_or_default();
 
         // While these predicates should all be implied by other parts of
         // the program, they are still relevant as they may constrain
index f35c5e44882df38db20a578bc83cdfcd9c2f50ae..27dc16259926bdba9b1c044781edfcf567e3c4b0 100644 (file)
@@ -6,6 +6,7 @@
 use rustc_middle::ty::{self, FnSig, Lift, PolyFnSig, Ty, TyCtxt, TypeFoldable};
 use rustc_middle::ty::{ParamEnvAnd, Predicate};
 use rustc_middle::ty::{UserSelfTy, UserSubsts, UserType};
+use rustc_span::def_id::CRATE_DEF_ID;
 use rustc_span::{Span, DUMMY_SP};
 use rustc_trait_selection::infer::InferCtxtBuilderExt;
 use rustc_trait_selection::traits::query::normalize::QueryNormalizeExt;
@@ -76,7 +77,6 @@ fn relate_mir_and_user_ty<'tcx>(
     // FIXME(#104764): We should check well-formedness before normalization.
     let predicate = ty::Binder::dummy(ty::PredicateKind::WellFormed(user_ty.into()));
     ocx.register_obligation(Obligation::new(ocx.infcx.tcx, cause, param_env, predicate));
-
     Ok(())
 }
 
@@ -111,7 +111,7 @@ fn relate_mir_and_user_substs<'tcx>(
         let span = if span == DUMMY_SP { predicate_span } else { span };
         let cause = ObligationCause::new(
             span,
-            hir::CRATE_HIR_ID,
+            CRATE_DEF_ID,
             ObligationCauseCode::AscribeUserTypeProvePredicate(predicate_span),
         );
         let instantiated_predicate =
@@ -126,7 +126,6 @@ fn relate_mir_and_user_substs<'tcx>(
         let impl_self_ty = ocx.normalize(&cause, param_env, impl_self_ty);
 
         ocx.eq(&cause, param_env, self_ty, impl_self_ty)?;
-
         let predicate = ty::Binder::dummy(ty::PredicateKind::WellFormed(impl_self_ty.into()));
         ocx.register_obligation(Obligation::new(tcx, cause.clone(), param_env, predicate));
     }
index 91a505a72fae7a6be74b31e2b2ff0909af29b877..e47e68e0670b9475a19080561dade3f4098940c3 100644 (file)
@@ -244,7 +244,7 @@ fn adjust_for_rust_scalar<'tcx>(
     }
 
     // Only pointer types handled below.
-    let Scalar::Initialized { value: Pointer, valid_range} = scalar else { return };
+    let Scalar::Initialized { value: Pointer(_), valid_range} = scalar else { return };
 
     if !valid_range.contains(0) {
         attrs.set(ArgAttribute::NonNull);
@@ -479,7 +479,7 @@ fn fn_abi_adjust_for_abi<'tcx>(
             }
 
             let size = arg.layout.size;
-            if arg.layout.is_unsized() || size > Pointer.size(cx) {
+            if arg.layout.is_unsized() || size > Pointer(AddressSpace::DATA).size(cx) {
                 arg.make_indirect();
             } else {
                 // We want to pass small aggregates as immediates, but using
index 6aa016133ca598926fffa1b2823962b11332da92..0f25579c7bfa19f8fc609ce9adabd167f9e37116 100644 (file)
@@ -134,7 +134,7 @@ fn layout_of_uncached<'tcx>(
             ty::FloatTy::F64 => F64,
         }),
         ty::FnPtr(_) => {
-            let mut ptr = scalar_unit(Pointer);
+            let mut ptr = scalar_unit(Pointer(dl.instruction_address_space));
             ptr.valid_range_mut().start = 1;
             tcx.intern_layout(LayoutS::scalar(cx, ptr))
         }
@@ -144,7 +144,7 @@ fn layout_of_uncached<'tcx>(
 
         // Potentially-wide pointers.
         ty::Ref(_, pointee, _) | ty::RawPtr(ty::TypeAndMut { ty: pointee, .. }) => {
-            let mut data_ptr = scalar_unit(Pointer);
+            let mut data_ptr = scalar_unit(Pointer(AddressSpace::DATA));
             if !ty.is_unsafe_ptr() {
                 data_ptr.valid_range_mut().start = 1;
             }
@@ -178,7 +178,7 @@ fn layout_of_uncached<'tcx>(
                     }
                     ty::Slice(_) | ty::Str => scalar_unit(Int(dl.ptr_sized_integer(), false)),
                     ty::Dynamic(..) => {
-                        let mut vtable = scalar_unit(Pointer);
+                        let mut vtable = scalar_unit(Pointer(AddressSpace::DATA));
                         vtable.valid_range_mut().start = 1;
                         vtable
                     }
@@ -195,7 +195,7 @@ fn layout_of_uncached<'tcx>(
         ty::Dynamic(_, _, ty::DynStar) => {
             let mut data = scalar_unit(Int(dl.ptr_sized_integer(), false));
             data.valid_range_mut().start = 0;
-            let mut vtable = scalar_unit(Pointer);
+            let mut vtable = scalar_unit(Pointer(AddressSpace::DATA));
             vtable.valid_range_mut().start = 1;
             tcx.intern_layout(cx.scalar_pair(data, vtable))
         }
index eb5454bf2634b6b61f948a265efea3b59a0ed8c5..13a76648690165bad418ae07618afcb7dd76e5d9 100644 (file)
@@ -1,8 +1,8 @@
 use rustc_data_structures::fx::FxIndexSet;
 use rustc_hir as hir;
-use rustc_hir::def_id::DefId;
 use rustc_middle::ty::{self, Binder, Predicate, PredicateKind, ToPredicate, Ty, TyCtxt};
 use rustc_session::config::TraitSolver;
+use rustc_span::def_id::{DefId, CRATE_DEF_ID};
 use rustc_trait_selection::traits;
 
 fn sized_constraint_for_ty<'tcx>(
@@ -208,14 +208,7 @@ fn param_env(tcx: TyCtxt<'_>, def_id: DefId) -> ty::ParamEnv<'_> {
         constness,
     );
 
-    let body_id =
-        local_did.and_then(|id| tcx.hir().maybe_body_owned_by(id).map(|body| body.hir_id));
-    let body_id = match body_id {
-        Some(id) => id,
-        None if hir_id.is_some() => hir_id.unwrap(),
-        _ => hir::CRATE_HIR_ID,
-    };
-
+    let body_id = local_did.unwrap_or(CRATE_DEF_ID);
     let cause = traits::ObligationCause::misc(tcx.def_span(def_id), body_id);
     traits::normalize_param_env_or_error(tcx, unnormalized_env, cause)
 }
index 129213fde7491c8ef02040003c6dc7314af694de..7f109491350f0a21c2bbb5bc3f6b0badd193e4e8 100644 (file)
 use crate::fmt::{self, Debug, Display};
 use crate::marker::{PhantomData, Unsize};
 use crate::mem;
-use crate::ops::{CoerceUnsized, Deref, DerefMut};
+use crate::ops::{CoerceUnsized, Deref, DerefMut, DispatchFromDyn};
 use crate::ptr::{self, NonNull};
 
 mod lazy;
@@ -571,6 +571,16 @@ pub fn take(&self) -> T {
 #[unstable(feature = "coerce_unsized", issue = "18598")]
 impl<T: CoerceUnsized<U>, U> CoerceUnsized<Cell<U>> for Cell<T> {}
 
+// Allow types that wrap `Cell` to also implement `DispatchFromDyn`
+// and become object safe method receivers.
+// Note that currently `Cell` itself cannot be a method receiver
+// because it does not implement Deref.
+// In other words:
+// `self: Cell<&Self>` won't work
+// `self: CellWrapper<Self>` becomes possible
+#[unstable(feature = "dispatch_from_dyn", issue = "none")]
+impl<T: DispatchFromDyn<U>, U> DispatchFromDyn<Cell<U>> for Cell<T> {}
+
 impl<T> Cell<[T]> {
     /// Returns a `&[Cell<T>]` from a `&Cell<[T]>`
     ///
@@ -2078,6 +2088,16 @@ fn from(t: T) -> UnsafeCell<T> {
 #[unstable(feature = "coerce_unsized", issue = "18598")]
 impl<T: CoerceUnsized<U>, U> CoerceUnsized<UnsafeCell<U>> for UnsafeCell<T> {}
 
+// Allow types that wrap `UnsafeCell` to also implement `DispatchFromDyn`
+// and become object safe method receivers.
+// Note that currently `UnsafeCell` itself cannot be a method receiver
+// because it does not implement Deref.
+// In other words:
+// `self: UnsafeCell<&Self>` won't work
+// `self: UnsafeCellWrapper<Self>` becomes possible
+#[unstable(feature = "dispatch_from_dyn", issue = "none")]
+impl<T: DispatchFromDyn<U>, U> DispatchFromDyn<UnsafeCell<U>> for UnsafeCell<T> {}
+
 /// [`UnsafeCell`], but [`Sync`].
 ///
 /// This is just an `UnsafeCell`, except it implements `Sync`
@@ -2169,6 +2189,17 @@ fn from(t: T) -> SyncUnsafeCell<T> {
 //#[unstable(feature = "sync_unsafe_cell", issue = "95439")]
 impl<T: CoerceUnsized<U>, U> CoerceUnsized<SyncUnsafeCell<U>> for SyncUnsafeCell<T> {}
 
+// Allow types that wrap `SyncUnsafeCell` to also implement `DispatchFromDyn`
+// and become object safe method receivers.
+// Note that currently `SyncUnsafeCell` itself cannot be a method receiver
+// because it does not implement Deref.
+// In other words:
+// `self: SyncUnsafeCell<&Self>` won't work
+// `self: SyncUnsafeCellWrapper<Self>` becomes possible
+#[unstable(feature = "dispatch_from_dyn", issue = "none")]
+//#[unstable(feature = "sync_unsafe_cell", issue = "95439")]
+impl<T: DispatchFromDyn<U>, U> DispatchFromDyn<SyncUnsafeCell<U>> for SyncUnsafeCell<T> {}
+
 #[allow(unused)]
 fn assert_coerce_unsized(
     a: UnsafeCell<&i32>,
index 7757068a4f2b97cbdbf606c90078e1d0fc3925ff..f74e563f1b9c0bc5ef8de2f77929c36c4d5633f9 100644 (file)
@@ -298,3 +298,7 @@ fn from(value: T) -> Self {
         OnceCell { inner: UnsafeCell::new(Some(value)) }
     }
 }
+
+// Just like for `Cell<T>` this isn't needed, but results in nicer error messages.
+#[unstable(feature = "once_cell", issue = "74465")]
+impl<T> !Sync for OnceCell<T> {}
index 2a7ec544f9e2e138804cf0c7720b70091d2d2927..c9821bf8109a7f39c43601292327994065131898 100644 (file)
@@ -267,6 +267,7 @@ pub fn new(buf: &'a mut (dyn Write + 'a)) -> Formatter<'a> {
 /// family of functions. It contains a function to format the given value. At
 /// compile time it is ensured that the function and the value have the correct
 /// types, and then this struct is used to canonicalize arguments to one type.
+#[cfg_attr(not(bootstrap), lang = "format_argument")]
 #[derive(Copy, Clone)]
 #[allow(missing_debug_implementations)]
 #[unstable(feature = "fmt_internals", reason = "internal to format_args!", issue = "none")]
@@ -279,6 +280,7 @@ pub struct ArgumentV1<'a> {
 /// This struct represents the unsafety of constructing an `Arguments`.
 /// It exists, rather than an unsafe function, in order to simplify the expansion
 /// of `format_args!(..)` and reduce the scope of the `unsafe` block.
+#[cfg_attr(not(bootstrap), lang = "format_unsafe_arg")]
 #[allow(missing_debug_implementations)]
 #[doc(hidden)]
 #[unstable(feature = "fmt_internals", reason = "internal to format_args!", issue = "none")]
@@ -473,8 +475,8 @@ pub fn estimated_capacity(&self) -> usize {
 /// ```
 ///
 /// [`format()`]: ../../std/fmt/fn.format.html
+#[cfg_attr(not(bootstrap), lang = "format_arguments")]
 #[stable(feature = "rust1", since = "1.0.0")]
-#[cfg_attr(not(test), rustc_diagnostic_item = "Arguments")]
 #[derive(Copy, Clone)]
 pub struct Arguments<'a> {
     // Format string pieces to print.
@@ -489,9 +491,26 @@ pub struct Arguments<'a> {
 }
 
 impl<'a> Arguments<'a> {
-    /// Get the formatted string, if it has no arguments to be formatted.
+    /// Get the formatted string, if it has no arguments to be formatted at runtime.
     ///
-    /// This can be used to avoid allocations in the most trivial case.
+    /// This can be used to avoid allocations in some cases.
+    ///
+    /// # Guarantees
+    ///
+    /// For `format_args!("just a literal")`, this function is guaranteed to
+    /// return `Some("just a literal")`.
+    ///
+    /// For most cases with placeholders, this function will return `None`.
+    ///
+    /// However, the compiler may perform optimizations that can cause this
+    /// function to return `Some(_)` even if the format string contains
+    /// placeholders. For example, `format_args!("Hello, {}!", "world")` may be
+    /// optimized to `format_args!("Hello, world!")`, such that `as_str()`
+    /// returns `Some("Hello, world!")`.
+    ///
+    /// The behavior for anything but the trivial case (without placeholders)
+    /// is not guaranteed, and should not be relied upon for anything other
+    /// than optimization.
     ///
     /// # Examples
     ///
@@ -512,7 +531,7 @@ impl<'a> Arguments<'a> {
     /// ```rust
     /// assert_eq!(format_args!("hello").as_str(), Some("hello"));
     /// assert_eq!(format_args!("").as_str(), Some(""));
-    /// assert_eq!(format_args!("{}", 1).as_str(), None);
+    /// assert_eq!(format_args!("{:?}", std::env::current_dir()).as_str(), None);
     /// ```
     #[stable(feature = "fmt_as_str", since = "1.52.0")]
     #[rustc_const_unstable(feature = "const_arguments_as_str", issue = "103900")]
index 37202b2774dc63d95086c9d7ef6d7fa3f6231742..11a50951a75dad1798ad15167388e895053f1ece 100644 (file)
@@ -5,7 +5,9 @@
 //! these can be statically allocated and are slightly optimized for the runtime
 #![allow(missing_debug_implementations)]
 
+#[cfg_attr(not(bootstrap), lang = "format_placeholder")]
 #[derive(Copy, Clone)]
+// FIXME: Rename this to Placeholder
 pub struct Argument {
     pub position: usize,
     pub format: FormatSpec,
@@ -20,7 +22,22 @@ pub struct FormatSpec {
     pub width: Count,
 }
 
+impl Argument {
+    #[inline(always)]
+    pub const fn new(
+        position: usize,
+        fill: char,
+        align: Alignment,
+        flags: u32,
+        precision: Count,
+        width: Count,
+    ) -> Self {
+        Self { position, format: FormatSpec { fill, align, flags, precision, width } }
+    }
+}
+
 /// Possible alignments that can be requested as part of a formatting directive.
+#[cfg_attr(not(bootstrap), lang = "format_alignment")]
 #[derive(Copy, Clone, PartialEq, Eq)]
 pub enum Alignment {
     /// Indication that contents should be left-aligned.
@@ -34,6 +51,7 @@ pub enum Alignment {
 }
 
 /// Used by [width](https://doc.rust-lang.org/std/fmt/#width) and [precision](https://doc.rust-lang.org/std/fmt/#precision) specifiers.
+#[cfg_attr(not(bootstrap), lang = "format_count")]
 #[derive(Copy, Clone)]
 pub enum Count {
     /// Specified with a literal number, stores the value
index e3157b66902eb9dbfbfafbc505bdb786c88cbb2b..3d7ccffa1735c97f5f54666aad381d06a22b5043 100644 (file)
 //!
 //! #### Statements
 //!  - Assign statements work via normal Rust assignment.
-//!  - [`Retag`] statements have an associated function.
+//!  - [`Retag`], [`StorageLive`], [`StorageDead`], [`Deinit`] statements have an associated function.
 //!
 //! #### Rvalues
 //!
 //!  - Operands implicitly convert to `Use` rvalues.
 //!  - `&`, `&mut`, `addr_of!`, and `addr_of_mut!` all work to create their associated rvalue.
-//!  - [`Discriminant`] has an associated function.
+//!  - [`Discriminant`] and [`Len`] have associated functions.
+//!  - Unary and binary operations use their normal Rust syntax - `a * b`, `!c`, etc.
+//!  - Checked binary operations are represented by wrapping the associated binop in [`Checked`].
+//!  - Array repetition syntax (`[foo; 10]`) creates the associated rvalue.
 //!
 //! #### Terminators
 //!
@@ -261,6 +264,9 @@ pub fn $($sig)* { panic!() }
 define!("mir_call", fn Call<T>(place: T, goto: BasicBlock, call: T));
 define!("mir_storage_live", fn StorageLive<T>(local: T));
 define!("mir_storage_dead", fn StorageDead<T>(local: T));
+define!("mir_deinit", fn Deinit<T>(place: T));
+define!("mir_checked", fn Checked<T>(binop: T) -> (T, bool));
+define!("mir_len", fn Len<T>(place: T) -> usize);
 define!("mir_retag", fn Retag<T>(place: T));
 define!("mir_move", fn Move<T>(place: T) -> T);
 define!("mir_static", fn Static<T>(s: T) -> &'static T);
index 1326fc9ab096f03d6edde634db009dc697c17c15..74055602ec2e62df6c58148f0725789d61faaf02 100644 (file)
@@ -469,6 +469,62 @@ pub trait Copy: Clone {
 #[cfg_attr(not(test), rustc_diagnostic_item = "Sync")]
 #[lang = "sync"]
 #[rustc_on_unimplemented(
+    on(
+        _Self = "std::cell::OnceCell<T>",
+        note = "if you want to do aliasing and mutation between multiple threads, use `std::sync::OnceLock` instead"
+    ),
+    on(
+        _Self = "std::cell::Cell<u8>",
+        note = "if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` or `std::sync::atomic::AtomicU8` instead",
+    ),
+    on(
+        _Self = "std::cell::Cell<u16>",
+        note = "if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` or `std::sync::atomic::AtomicU16` instead",
+    ),
+    on(
+        _Self = "std::cell::Cell<u32>",
+        note = "if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` or `std::sync::atomic::AtomicU32` instead",
+    ),
+    on(
+        _Self = "std::cell::Cell<u64>",
+        note = "if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` or `std::sync::atomic::AtomicU64` instead",
+    ),
+    on(
+        _Self = "std::cell::Cell<usize>",
+        note = "if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` or `std::sync::atomic::AtomicUsize` instead",
+    ),
+    on(
+        _Self = "std::cell::Cell<i8>",
+        note = "if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` or `std::sync::atomic::AtomicI8` instead",
+    ),
+    on(
+        _Self = "std::cell::Cell<i16>",
+        note = "if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` or `std::sync::atomic::AtomicI16` instead",
+    ),
+    on(
+        _Self = "std::cell::Cell<i32>",
+        note = "if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` or `std::sync::atomic::AtomicI32` instead",
+    ),
+    on(
+        _Self = "std::cell::Cell<i64>",
+        note = "if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` or `std::sync::atomic::AtomicI64` instead",
+    ),
+    on(
+        _Self = "std::cell::Cell<isize>",
+        note = "if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` or `std::sync::atomic::AtomicIsize` instead",
+    ),
+    on(
+        _Self = "std::cell::Cell<bool>",
+        note = "if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` or `std::sync::atomic::AtomicBool` instead",
+    ),
+    on(
+        _Self = "std::cell::Cell<T>",
+        note = "if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock`",
+    ),
+    on(
+        _Self = "std::cell::RefCell<T>",
+        note = "if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` instead",
+    ),
     message = "`{Self}` cannot be shared between threads safely",
     label = "`{Self}` cannot be shared between threads safely"
 )]
index 7b1cb5488bcac650871b9ee38de84fb536bef4e7..16eb726f6f61476294d3271abdbd21d4c3b00602 100644 (file)
@@ -731,7 +731,7 @@ pub fn mask(self, mask: usize) -> *const T {
     /// This computes the same value that [`offset_from`](#method.offset_from)
     /// would compute, but with the added precondition that the offset is
     /// guaranteed to be non-negative.  This method is equivalent to
-    /// `usize::from(self.offset_from(origin)).unwrap_unchecked()`,
+    /// `usize::try_from(self.offset_from(origin)).unwrap_unchecked()`,
     /// but it provides slightly more information to the optimizer, which can
     /// sometimes allow it to optimize slightly better with some backends.
     ///
index ed1e3bd48122761607f22a10f0bfb11608c0d892..0a2f63e3ec6a5fb1ecce6845f442790d1cfa7c4d 100644 (file)
@@ -904,7 +904,7 @@ pub const fn guaranteed_ne(self, other: *mut T) -> Option<bool>
     /// This computes the same value that [`offset_from`](#method.offset_from)
     /// would compute, but with the added precondition that the offset is
     /// guaranteed to be non-negative.  This method is equivalent to
-    /// `usize::from(self.offset_from(origin)).unwrap_unchecked()`,
+    /// `usize::try_from(self.offset_from(origin)).unwrap_unchecked()`,
     /// but it provides slightly more information to the optimizer, which can
     /// sometimes allow it to optimize slightly better with some backends.
     ///
index f0e4f5d8a8013d613098c4ecd0a2dfee921ac24a..938935771d64e24c84d775cd2c59472344a02a04 100644 (file)
@@ -74,6 +74,7 @@ pub fn is_available() -> bool {
 ///
 /// This is both the input and output of `#[proc_macro]`, `#[proc_macro_attribute]`
 /// and `#[proc_macro_derive]` definitions.
+#[rustc_diagnostic_item = "TokenStream"]
 #[stable(feature = "proc_macro_lib", since = "1.15.0")]
 #[derive(Clone)]
 pub struct TokenStream(Option<bridge::client::TokenStream>);
@@ -581,7 +582,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 
 /// A line-column pair representing the start or end of a `Span`.
 #[unstable(feature = "proc_macro_span", issue = "54725")]
-#[derive(Copy, Clone, Debug, PartialEq, Eq)]
+#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
 pub struct LineColumn {
     /// The 1-indexed line in the source file on which the span starts or ends (inclusive).
     #[unstable(feature = "proc_macro_span", issue = "54725")]
index c1e3e48b04468c8c501d45392b3c06b35fa34ac8..c6bb09b0417f3c918fd06b2b3a377b9829d2f592 100644 (file)
@@ -319,19 +319,10 @@ pub(crate) fn send(
     ) -> Result<(), SendTimeoutError<T>> {
         let token = &mut Token::default();
         loop {
-            // Try sending a message several times.
-            let backoff = Backoff::new();
-            loop {
-                if self.start_send(token) {
-                    let res = unsafe { self.write(token, msg) };
-                    return res.map_err(SendTimeoutError::Disconnected);
-                }
-
-                if backoff.is_completed() {
-                    break;
-                } else {
-                    backoff.spin_light();
-                }
+            // Try sending a message.
+            if self.start_send(token) {
+                let res = unsafe { self.write(token, msg) };
+                return res.map_err(SendTimeoutError::Disconnected);
             }
 
             if let Some(d) = deadline {
@@ -379,6 +370,7 @@ pub(crate) fn try_recv(&self) -> Result<T, TryRecvError> {
     pub(crate) fn recv(&self, deadline: Option<Instant>) -> Result<T, RecvTimeoutError> {
         let token = &mut Token::default();
         loop {
+            // Try receiving a message.
             if self.start_recv(token) {
                 let res = unsafe { self.read(token) };
                 return res.map_err(|_| RecvTimeoutError::Disconnected);
index cfe42750d5239a6a46ab629027581df795c12129..d053d69e26eeeb819c9da040bf8141870fc914b1 100644 (file)
@@ -105,10 +105,8 @@ pub fn new() -> Self {
 
     /// Backs off using lightweight spinning.
     ///
-    /// This method should be used for:
-    ///     - Retrying an operation because another thread made progress. i.e. on CAS failure.
-    ///     - Waiting for an operation to complete by spinning optimistically for a few iterations
-    ///     before falling back to parking the thread (see `Backoff::is_completed`).
+    /// This method should be used for retrying an operation because another thread made
+    /// progress. i.e. on CAS failure.
     #[inline]
     pub fn spin_light(&self) {
         let step = self.step.get().min(SPIN_LIMIT);
@@ -134,10 +132,4 @@ pub fn spin_heavy(&self) {
 
         self.step.set(self.step.get() + 1);
     }
-
-    /// Returns `true` if quadratic backoff has completed and parking the thread is advised.
-    #[inline]
-    pub fn is_completed(&self) -> bool {
-        self.step.get() > SPIN_LIMIT
-    }
 }
index c31fb3a48dabb474bda286a79d59a9fcfe9cc119..236d2f2ee29280cac96ce34c512c7bae291a0786 100644 (file)
 // Note, however, that we run on lots older linuxes, as well as cross
 // compiling from a newer linux to an older linux, so we also have a
 // fallback implementation to use as well.
-#[cfg(any(
-    target_os = "linux",
-    target_os = "fuchsia",
-    target_os = "redox",
-    target_os = "emscripten"
-))]
-#[cfg_attr(target_family = "wasm", allow(unused))] // might remain unused depending on target details (e.g. wasm32-unknown-emscripten)
+#[cfg(any(target_os = "linux", target_os = "fuchsia", target_os = "redox"))]
 pub unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern "C" fn(*mut u8)) {
     use crate::mem;
     use crate::sys_common::thread_local_dtor::register_dtor_fallback;
@@ -89,7 +83,8 @@ pub unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern "C" fn(*mut u8)) {
     }
 }
 
-#[cfg(any(target_os = "vxworks", target_os = "horizon"))]
+#[cfg(any(target_os = "vxworks", target_os = "horizon", target_os = "emscripten"))]
+#[cfg_attr(target_family = "wasm", allow(unused))] // might remain unused depending on target details (e.g. wasm32-unknown-emscripten)
 pub unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern "C" fn(*mut u8)) {
     use crate::sys_common::thread_local_dtor::register_dtor_fallback;
     register_dtor_fallback(t, dtor);
index 1a2c125566139d11370637b368d3d954314586ff..bf3c81fcc980b95968583fe33b0ccdaebe0a3b48 100644 (file)
@@ -120,16 +120,13 @@ fn x86_all() {
     println!("avx512dq: {:?}", is_x86_feature_detected!("avx512dq"));
     println!("avx512er: {:?}", is_x86_feature_detected!("avx512er"));
     println!("avx512f: {:?}", is_x86_feature_detected!("avx512f"));
-    println!("avx512gfni: {:?}", is_x86_feature_detected!("avx512gfni"));
     println!("avx512ifma: {:?}", is_x86_feature_detected!("avx512ifma"));
     println!("avx512pf: {:?}", is_x86_feature_detected!("avx512pf"));
-    println!("avx512vaes: {:?}", is_x86_feature_detected!("avx512vaes"));
     println!("avx512vbmi2: {:?}", is_x86_feature_detected!("avx512vbmi2"));
     println!("avx512vbmi: {:?}", is_x86_feature_detected!("avx512vbmi"));
     println!("avx512vl: {:?}", is_x86_feature_detected!("avx512vl"));
     println!("avx512vnni: {:?}", is_x86_feature_detected!("avx512vnni"));
     println!("avx512vp2intersect: {:?}", is_x86_feature_detected!("avx512vp2intersect"));
-    println!("avx512vpclmulqdq: {:?}", is_x86_feature_detected!("avx512vpclmulqdq"));
     println!("avx512vpopcntdq: {:?}", is_x86_feature_detected!("avx512vpopcntdq"));
     println!("avx: {:?}", is_x86_feature_detected!("avx"));
     println!("bmi1: {:?}", is_x86_feature_detected!("bmi1"));
@@ -138,6 +135,7 @@ fn x86_all() {
     println!("f16c: {:?}", is_x86_feature_detected!("f16c"));
     println!("fma: {:?}", is_x86_feature_detected!("fma"));
     println!("fxsr: {:?}", is_x86_feature_detected!("fxsr"));
+    println!("gfni: {:?}", is_x86_feature_detected!("gfni"));
     println!("lzcnt: {:?}", is_x86_feature_detected!("lzcnt"));
     //println!("movbe: {:?}", is_x86_feature_detected!("movbe")); // movbe is unsupported as a target feature
     println!("pclmulqdq: {:?}", is_x86_feature_detected!("pclmulqdq"));
@@ -154,6 +152,8 @@ fn x86_all() {
     println!("sse: {:?}", is_x86_feature_detected!("sse"));
     println!("ssse3: {:?}", is_x86_feature_detected!("ssse3"));
     println!("tbm: {:?}", is_x86_feature_detected!("tbm"));
+    println!("vaes: {:?}", is_x86_feature_detected!("vaes"));
+    println!("vpclmulqdq: {:?}", is_x86_feature_detected!("vpclmulqdq"));
     println!("xsave: {:?}", is_x86_feature_detected!("xsave"));
     println!("xsavec: {:?}", is_x86_feature_detected!("xsavec"));
     println!("xsaveopt: {:?}", is_x86_feature_detected!("xsaveopt"));
index 790411f93c4b5eada3c23abb4c9a063fb0b24d99..a0c30f3e3c75adcd6ee7efc94014ebcead61c507 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 790411f93c4b5eada3c23abb4c9a063fb0b24d99
+Subproject commit a0c30f3e3c75adcd6ee7efc94014ebcead61c507
index 796796e07a9c18fe5673961f463753cf980e2763..9d22ebbee873bab9b680fd37e9fde055e932c3c6 100644 (file)
@@ -309,7 +309,8 @@ fn parse_opts_impl(matches: getopts::Matches) -> OptRes {
 // FIXME: Copied from librustc_ast until linkage errors are resolved. Issue #47566
 fn is_nightly() -> bool {
     // Whether this is a feature-staged build, i.e., on the beta or stable channel
-    let disable_unstable_features = option_env!("CFG_DISABLE_UNSTABLE_FEATURES").is_some();
+    let disable_unstable_features =
+        option_env!("CFG_DISABLE_UNSTABLE_FEATURES").map(|s| s != "0").unwrap_or(false);
     // Whether we should enable unstable features for bootstrapping
     let bootstrap = env::var("RUSTC_BOOTSTRAP").is_ok();
 
index be69f819c6428f8e88332ab7889656ec7482a88a..3856bb64fb310331f44899dcd940708335e4e24c 100644 (file)
@@ -16,12 +16,17 @@ fn main() {
     let mut build_lock;
     let _build_lock_guard;
     if cfg!(any(unix, windows)) {
-        build_lock = fd_lock::RwLock::new(t!(std::fs::File::create(config.out.join("lock"))));
+        let path = config.out.join("lock");
+        build_lock = fd_lock::RwLock::new(t!(std::fs::File::create(&path)));
         _build_lock_guard = match build_lock.try_write() {
             Ok(lock) => lock,
             err => {
-                println!("warning: build directory locked, waiting for lock");
                 drop(err);
+                if let Some(pid) = get_lock_owner(&path) {
+                    println!("warning: build directory locked by process {pid}, waiting for lock");
+                } else {
+                    println!("warning: build directory locked, waiting for lock");
+                }
                 t!(build_lock.write())
             }
         };
@@ -98,3 +103,30 @@ fn check_version(config: &Config) -> Option<String> {
 
     Some(msg)
 }
+
+/// Get the PID of the process which took the write lock by
+/// parsing `/proc/locks`.
+#[cfg(target_os = "linux")]
+fn get_lock_owner(f: &std::path::Path) -> Option<u64> {
+    use std::fs::File;
+    use std::io::{BufRead, BufReader};
+    use std::os::unix::fs::MetadataExt;
+
+    let lock_inode = std::fs::metadata(f).ok()?.ino();
+    let lockfile = File::open("/proc/locks").ok()?;
+    BufReader::new(lockfile).lines().find_map(|line| {
+        //                       pid--vvvvvv       vvvvvvv--- inode
+        // 21: FLOCK  ADVISORY  WRITE 359238 08:02:3719774 0 EOF
+        let line = line.ok()?;
+        let parts = line.split_whitespace().collect::<Vec<_>>();
+        let (pid, inode) = (parts[4].parse::<u64>().ok()?, &parts[5]);
+        let inode = inode.rsplit_once(':')?.1.parse::<u64>().ok()?;
+        if inode == lock_inode { Some(pid) } else { None }
+    })
+}
+
+#[cfg(not(target_os = "linux"))]
+fn get_lock_owner(_: &std::path::Path) -> Option<u64> {
+    // FIXME: Implement on other OS's
+    None
+}
index 2d86ff1d2baeafff219b642ca5e5338bfd84cf01..02e35d2436e2f48b4e4b3a40f1ae758e49ea665a 100644 (file)
@@ -962,7 +962,7 @@ fn run(self, builder: &Builder<'_>) -> GeneratedTarball {
             "Cargo.toml",
             "Cargo.lock",
         ];
-        let src_dirs = ["src", "compiler", "library"];
+        let src_dirs = ["src", "compiler", "library", "tests"];
 
         copy_src_dirs(builder, &builder.src, &src_dirs, &[], &plain_dst_src);
 
index d3dc4065dfc7230d98cc259d7853633a4f2236a4..33404a76835975da4e656f3f8bff6f5952116202 100644 (file)
@@ -1064,14 +1064,8 @@ fn fmt_type<'cx>(
                     fmt_type(ty, f, use_absolute, cx)?;
                     write!(f, ")")
                 }
-                clean::Generic(..) => {
-                    primitive_link(
-                        f,
-                        PrimitiveType::Reference,
-                        &format!("{}{}{}", amp, lt, m),
-                        cx,
-                    )?;
-                    fmt_type(ty, f, use_absolute, cx)
+                clean::Generic(name) => {
+                    primitive_link(f, PrimitiveType::Reference, &format!("{amp}{lt}{m}{name}"), cx)
                 }
                 _ => {
                     write!(f, "{}{}{}", amp, lt, m)?;
index 424bbb0ec42be8a1e42765ebc29638de8bc6a399..bf83ff2044e696385679555cf00eb38dcd10bb8f 100644 (file)
@@ -533,7 +533,7 @@ ul.block, .block li {
 .rustdoc .example-wrap > pre {
        margin: 0;
        flex-grow: 1;
-       overflow-x: auto;
+       overflow: auto hidden;
 }
 
 .rustdoc .example-wrap > pre.example-line-numbers,
index 4e9803fe2366d2adf3b0b46d905134d4520ba9ca..c28cefebc8bf5fccf3796a295959267f6a945810 100644 (file)
@@ -3,8 +3,7 @@
        position: relative;
 }
 
-.setting-line .radio-line input,
-.setting-line .settings-toggle input {
+.setting-radio input, .setting-check input {
        margin-right: 0.3em;
        height: 1.2rem;
        width: 1.2rem;
        -webkit-appearance: none;
        cursor: pointer;
 }
-.setting-line .radio-line input {
+.setting-radio input {
        border-radius: 50%;
 }
-.setting-line .settings-toggle input:checked {
+.setting-check input:checked {
        content: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40">\
                <path d="M7,25L17,32L33,12" fill="none" stroke="black" stroke-width="5"/>\
                <path d="M7,23L17,30L33,10" fill="none" stroke="white" stroke-width="5"/></svg>');
 }
 
-.setting-line .radio-line input + span,
-.setting-line .settings-toggle span {
+.setting-radio span, .setting-check span {
        padding-bottom: 1px;
 }
 
-.radio-line .choice {
+.setting-radio {
        margin-top: 0.1em;
        margin-bottom: 0.1em;
        min-width: 3.8em;
        align-items: center;
        cursor: pointer;
 }
-.radio-line .choice + .choice {
+.setting-radio + .setting-radio {
        margin-left: 0.5em;
 }
 
-.settings-toggle {
+.setting-check {
        position: relative;
        width: 100%;
        margin-right: 20px;
        cursor: pointer;
 }
 
-.setting-line .radio-line input:checked {
+.setting-radio input:checked {
        box-shadow: inset 0 0 0 3px var(--main-background-color);
        background-color: var(--settings-input-color);
 }
-.setting-line .settings-toggle input:checked {
+.setting-check input:checked {
        background-color: var(--settings-input-color);
 }
-.setting-line .radio-line input:focus,
-.setting-line .settings-toggle input:focus {
+.setting-radio input:focus, .setting-check input:focus {
        box-shadow: 0 0 1px 1px var(--settings-input-color);
 }
 /* In here we combine both `:focus` and `:checked` properties. */
-.setting-line .radio-line input:checked:focus {
+.setting-radio input:checked:focus {
        box-shadow: inset 0 0 0 3px var(--main-background-color),
                0 0 2px 2px var(--settings-input-color);
 }
-.setting-line .radio-line input:hover,
-.setting-line .settings-toggle input:hover {
+.setting-radio input:hover, .setting-check input:hover {
        border-color: var(--settings-input-color) !important;
 }
index 84df1b7d3911a4ecf0d3209afa4cee6f5466b079..a841b4b63bae8c1c557fd29475bcb6f016144380 100644 (file)
     }
 
     function showLightAndDark() {
-        removeClass(document.getElementById("preferred-light-theme").parentElement, "hidden");
-        removeClass(document.getElementById("preferred-dark-theme").parentElement, "hidden");
+        removeClass(document.getElementById("preferred-light-theme"), "hidden");
+        removeClass(document.getElementById("preferred-dark-theme"), "hidden");
     }
 
     function hideLightAndDark() {
-        addClass(document.getElementById("preferred-light-theme").parentElement, "hidden");
-        addClass(document.getElementById("preferred-dark-theme").parentElement, "hidden");
+        addClass(document.getElementById("preferred-light-theme"), "hidden");
+        addClass(document.getElementById("preferred-dark-theme"), "hidden");
     }
 
     function updateLightAndDark() {
             toggle.onkeyup = handleKey;
             toggle.onkeyrelease = handleKey;
         });
-        onEachLazy(settingsElement.getElementsByClassName("select-wrapper"), elem => {
-            const select = elem.getElementsByTagName("select")[0];
-            const settingId = select.id;
-            const settingValue = getSettingValue(settingId);
-            if (settingValue !== null) {
-                select.value = settingValue;
-            }
-            select.onchange = function() {
-                changeSetting(this.id, this.value);
-            };
-        });
         onEachLazy(settingsElement.querySelectorAll("input[type=\"radio\"]"), elem => {
             const settingId = elem.name;
             let settingValue = getSettingValue(settingId);
         let output = "";
 
         for (const setting of settings) {
-            output += "<div class=\"setting-line\">";
             const js_data_name = setting["js_name"];
             const setting_name = setting["name"];
 
             if (setting["options"] !== undefined) {
                 // This is a select setting.
                 output += `\
-<div class="radio-line" id="${js_data_name}">
-    <div class="setting-name">${setting_name}</div>
-<div class="choices">`;
+<div class="setting-line" id="${js_data_name}">
+    <div class="setting-radio-name">${setting_name}</div>
+    <div class="setting-radio-choices">`;
                 onEach(setting["options"], option => {
                     const checked = option === setting["default"] ? " checked" : "";
                     const full = `${js_data_name}-${option.replace(/ /g,"-")}`;
 
                     output += `\
-<label for="${full}" class="choice">
-    <input type="radio" name="${js_data_name}"
-        id="${full}" value="${option}"${checked}>
-    <span>${option}</span>
-</label>`;
+        <label for="${full}" class="setting-radio">
+            <input type="radio" name="${js_data_name}"
+                id="${full}" value="${option}"${checked}>
+            <span>${option}</span>
+        </label>`;
                 });
-                output += "</div></div>";
+                output += `\
+    </div>
+</div>`;
             } else {
                 // This is a checkbox toggle.
                 const checked = setting["default"] === true ? " checked" : "";
                 output += `\
-<label class="settings-toggle">\
-    <input type="checkbox" id="${js_data_name}"${checked}>\
-    <span class="label">${setting_name}</span>\
-</label>`;
+<div class="setting-line">\
+    <label class="setting-check">\
+        <input type="checkbox" id="${js_data_name}"${checked}>\
+        <span>${setting_name}</span>\
+    </label>\
+</div>`;
             }
-            output += "</div>";
         }
         return output;
     }
index 86454e1f2eb7316d239d4544c3adeec49e917e89..a689b502f0fccb1d3fe8fd81059c9dcecba64b90 100644 (file)
@@ -815,7 +815,7 @@ fn main_args(at_args: &[String]) -> MainResult {
                 sess.fatal("Compilation failed, aborting rustdoc");
             }
 
-            let global_ctxt = abort_on_err(queries.global_ctxt(), sess);
+            let mut global_ctxt = abort_on_err(queries.global_ctxt(), sess);
 
             global_ctxt.enter(|tcx| {
                 let (krate, render_opts, mut cache) = sess.time("run_global_ctxt", || {
index 985d561f0bb9b76ec043a2b12511790ec7a2b954..3c5af6bed9a1a243a693e8e22ee2486bd5b82a6c 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 985d561f0bb9b76ec043a2b12511790ec7a2b954
+Subproject commit 3c5af6bed9a1a243a693e8e22ee2486bd5b82a6c
index 043112bbc95967dc66c3814e3d02013ff76932cf..70a80d40f464bbbd5bbabac0b0be673742b557b3 100644 (file)
@@ -7,14 +7,14 @@
 };
 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::ty::{implements_trait, is_type_lang_item};
 use if_chain::if_chain;
 use itertools::Itertools;
 use rustc_errors::{
     Applicability,
     SuggestionStyle::{CompletelyHidden, ShowCode},
 };
-use rustc_hir::{Expr, ExprKind, HirId, QPath};
+use rustc_hir::{Expr, ExprKind, HirId, LangItem, QPath};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
 use rustc_middle::ty::adjustment::{Adjust, Adjustment};
 use rustc_middle::ty::Ty;
@@ -237,7 +237,7 @@ fn check_unused_format_specifier(cx: &LateContext<'_>, arg: &FormatArg<'_>) {
         );
     }
 
-    if is_type_diagnostic_item(cx, param_ty, sym::Arguments) && !arg.format.is_default_for_trait() {
+    if is_type_lang_item(cx, param_ty, LangItem::FormatArguments) && !arg.format.is_default_for_trait() {
         span_lint_and_then(
             cx,
             UNUSED_FORMAT_SPECS,
index 989f83cf80d5972301fc06eef9604796f674a7b8..2a79b18b829941c4a218843a84a135fc8b83a0ae 100644 (file)
@@ -78,7 +78,8 @@ fn check_fn(
                 let send_trait = cx.tcx.get_diagnostic_item(sym::Send).unwrap();
                 let span = decl.output.span();
                 let infcx = cx.tcx.infer_ctxt().build();
-                let cause = traits::ObligationCause::misc(span, hir_id);
+                let def_id = cx.tcx.hir().local_def_id(hir_id);
+                let cause = traits::ObligationCause::misc(span, def_id);
                 let send_errors = traits::fully_solve_bound(&infcx, cause, cx.param_env, ret_ty, send_trait);
                 if !send_errors.is_empty() {
                     span_lint_and_then(
index 9263f0519724bcaa58d30f45ef2c05d6569ec230..b812e81cb107b35a217694df38a8fa3865889205 100644 (file)
@@ -371,7 +371,7 @@ fn can_change_type<'a>(cx: &LateContext<'a>, mut expr: &'a Expr<'a>, mut ty: Ty<
                 && let output_ty = return_ty(cx, item.hir_id())
                 && let local_def_id = cx.tcx.hir().local_def_id(item.hir_id())
                 && Inherited::build(cx.tcx, local_def_id).enter(|inherited| {
-                    let fn_ctxt = FnCtxt::new(inherited, cx.param_env, item.hir_id());
+                    let fn_ctxt = FnCtxt::new(inherited, cx.param_env, local_def_id);
                     fn_ctxt.can_coerce(ty, output_ty)
                 }) {
                     if has_lifetime(output_ty) && has_lifetime(ty) {
index 49d863ec03f1d014c575c776da02a9b3c712d1ba..b59d52dfc4d313b9b2b8e99719aeb483ffc7bba2 100644 (file)
@@ -46,7 +46,7 @@ fn check_cast<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>, from_ty: Ty<'tcx>
     let local_def_id = hir_id.owner.def_id;
 
     Inherited::build(cx.tcx, local_def_id).enter(|inherited| {
-        let fn_ctxt = FnCtxt::new(inherited, cx.param_env, hir_id);
+        let fn_ctxt = FnCtxt::new(inherited, cx.param_env, local_def_id);
 
         // If we already have errors, we can't be sure we can pointer cast.
         assert!(
index 77c5f1155423c4a7a4399694988e3b56442bae5a..a8f8da67b51711807ba146c7577bb4a93870086b 100644 (file)
@@ -1,6 +1,5 @@
 #![allow(clippy::similar_names)] // `expr` and `expn`
 
-use crate::is_path_diagnostic_item;
 use crate::source::snippet_opt;
 use crate::visitors::{for_each_expr, Descend};
 
@@ -8,7 +7,7 @@
 use itertools::{izip, Either, Itertools};
 use rustc_ast::ast::LitKind;
 use rustc_hir::intravisit::{walk_expr, Visitor};
-use rustc_hir::{self as hir, Expr, ExprField, ExprKind, HirId, Node, QPath};
+use rustc_hir::{self as hir, Expr, ExprField, ExprKind, HirId, LangItem, Node, QPath, TyKind};
 use rustc_lexer::unescape::unescape_literal;
 use rustc_lexer::{tokenize, unescape, LiteralKind, TokenKind};
 use rustc_lint::LateContext;
@@ -439,8 +438,7 @@ fn new(args: &'tcx Expr<'tcx>, format_string_span: SpanData) -> Self {
                 // ArgumentV1::from_usize(<val>)
                 if let ExprKind::Call(callee, [val]) = expr.kind
                     && let ExprKind::Path(QPath::TypeRelative(ty, _)) = callee.kind
-                    && let hir::TyKind::Path(QPath::Resolved(_, path)) = ty.kind
-                    && path.segments.last().unwrap().ident.name == sym::ArgumentV1
+                    && let TyKind::Path(QPath::LangItem(LangItem::FormatArgument, _, _)) = ty.kind
                 {
                     let val_idx = if val.span.ctxt() == expr.span.ctxt()
                         && let ExprKind::Field(_, field) = val.kind
@@ -486,20 +484,6 @@ struct ParamPosition {
 
 impl<'tcx> Visitor<'tcx> for ParamPosition {
     fn visit_expr_field(&mut self, field: &'tcx ExprField<'tcx>) {
-        fn parse_count(expr: &Expr<'_>) -> Option<usize> {
-            // ::core::fmt::rt::v1::Count::Param(1usize),
-            if let ExprKind::Call(ctor, [val]) = expr.kind
-                && let ExprKind::Path(QPath::Resolved(_, path)) = ctor.kind
-                && path.segments.last()?.ident.name == sym::Param
-                && let ExprKind::Lit(lit) = &val.kind
-                && let LitKind::Int(pos, _) = lit.node
-            {
-                Some(pos as usize)
-            } else {
-                None
-            }
-        }
-
         match field.ident.name {
             sym::position => {
                 if let ExprKind::Lit(lit) = &field.expr.kind
@@ -519,15 +503,41 @@ fn parse_count(expr: &Expr<'_>) -> Option<usize> {
     }
 }
 
+fn parse_count(expr: &Expr<'_>) -> Option<usize> {
+    // <::core::fmt::rt::v1::Count>::Param(1usize),
+    if let ExprKind::Call(ctor, [val]) = expr.kind
+        && let ExprKind::Path(QPath::TypeRelative(_, path)) = ctor.kind
+            && path.ident.name == sym::Param
+            && let ExprKind::Lit(lit) = &val.kind
+            && let LitKind::Int(pos, _) = lit.node
+    {
+        Some(pos as usize)
+    } else {
+        None
+    }
+}
+
 /// Parses the `fmt` arg of `Arguments::new_v1_formatted(pieces, args, fmt, _)`
 fn parse_rt_fmt<'tcx>(fmt_arg: &'tcx Expr<'tcx>) -> Option<impl Iterator<Item = ParamPosition> + 'tcx> {
     if let ExprKind::AddrOf(.., array) = fmt_arg.kind
         && let ExprKind::Array(specs) = array.kind
     {
         Some(specs.iter().map(|spec| {
-            let mut position = ParamPosition::default();
-            position.visit_expr(spec);
-            position
+            if let ExprKind::Call(f, args) = spec.kind
+                && let ExprKind::Path(QPath::TypeRelative(ty, f)) = f.kind
+                && let TyKind::Path(QPath::LangItem(LangItem::FormatPlaceholder, _, _)) = ty.kind
+                && f.ident.name == sym::new
+                && let [position, _fill, _align, _flags, precision, width] = args
+                && let ExprKind::Lit(position) = &position.kind
+                && let LitKind::Int(position, _) = position.node {
+                    ParamPosition {
+                        value: position as usize,
+                        width: parse_count(width),
+                        precision: parse_count(precision),
+                    }
+            } else {
+                ParamPosition::default()
+            }
         }))
     } else {
         None
@@ -890,7 +900,7 @@ pub fn parse(cx: &LateContext<'_>, expr: &'tcx Expr<'tcx>) -> Option<Self> {
         // ::core::fmt::Arguments::new_v1_formatted(pieces, args, fmt, _unsafe_arg)
         if let ExprKind::Call(callee, [pieces, args, rest @ ..]) = expr.kind
             && let ExprKind::Path(QPath::TypeRelative(ty, seg)) = callee.kind
-            && is_path_diagnostic_item(cx, ty, sym::Arguments)
+            && let TyKind::Path(QPath::LangItem(LangItem::FormatArguments, _, _)) = ty.kind
             && matches!(seg.ident.as_str(), "new_v1" | "new_v1_formatted")
         {
             let format_string = FormatString::new(cx, pieces)?;
index e7879bb196e428d3597b88d52d8d30fe83df6414..2d1044af17e8c331c0a964cb6330ff5ea2290ad4 100644 (file)
@@ -219,6 +219,7 @@ pub fn ast(
             | ast::ExprKind::Repeat(..)
             | ast::ExprKind::Ret(..)
             | ast::ExprKind::Yeet(..)
+            | ast::ExprKind::FormatArgs(..)
             | ast::ExprKind::Struct(..)
             | ast::ExprKind::Try(..)
             | ast::ExprKind::TryBlock(..)
diff --git a/src/tools/rustfmt/.github/workflows/check_diff.yml b/src/tools/rustfmt/.github/workflows/check_diff.yml
new file mode 100644 (file)
index 0000000..8bfb583
--- /dev/null
@@ -0,0 +1,33 @@
+name: Diff Check
+on:
+  workflow_dispatch:
+    inputs:
+      clone_url:
+        description: 'Git url of a rustfmt fork to compare against the latest master rustfmt'
+        required: true
+      branch_name:
+        description: 'Name of the feature branch on the forked repo'
+        required: true
+      commit_hash:
+        description: 'Optional commit hash from the feature branch'
+        required: false
+      rustfmt_configs:
+        description: 'Optional comma separated list of rustfmt config options to pass when running the feature branch'
+        required: false
+
+jobs:
+  diff_check:
+    runs-on: ubuntu-latest
+
+    steps:
+    - name: checkout
+      uses: actions/checkout@v3
+
+    - name: install rustup
+      run: |
+        curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs > rustup-init.sh
+        sh rustup-init.sh -y --default-toolchain none
+        rustup target add x86_64-unknown-linux-gnu
+
+    - name: check diff
+      run: bash ${GITHUB_WORKSPACE}/ci/check_diff.sh ${{ github.event.inputs.clone_url }} ${{ github.event.inputs.branch_name }} ${{ github.event.inputs.commit_hash }} ${{ github.event.inputs.rustfmt_configs }}
index 4d8899b434bbe8c03abd5bd09cb576f7af460a07..314ce0e84c61b666ef16536e44fb681030034a18 100644 (file)
@@ -27,7 +27,6 @@ jobs:
           tempdir,
           futures-rs,
           rust-clippy,
-          failure,
         ]
         include:
           # Allowed Failures
@@ -63,9 +62,6 @@ jobs:
           # Original comment was: temporal build failure due to breaking changes in the nightly compiler
           - integration: rust-semverver
             allow-failure: true
-          # Can be moved back to include section after https://github.com/rust-lang-nursery/failure/pull/298 is merged
-          - integration: failure
-            allow-failure: true
 
     steps:
     - name: checkout
index 0c1893bf8c387f1ddd72f8958cc0885589159dcc..60f961fa12ac832556cf23e3f3cd199e823595e0 100644 (file)
@@ -2,6 +2,32 @@
 
 ## [Unreleased]
 
+## [1.5.2] 2023-01-24
+
+### Fixed
+
+- Resolve issue when comments are found within const generic defaults in unit structs [#5668](https://github.com/rust-lang/rustfmt/issues/5668)
+- Resolve issue when block comments are found within trait generics [#5358](https://github.com/rust-lang/rustfmt/issues/5358)
+- Correctly handle alignment of comments containing unicode characters [#5504](https://github.com/rust-lang/rustfmt/issues/5504)
+- Properly indent a single generic bound that requires being written across multiple lines [#4689](https://github.com/rust-lang/rustfmt/issues/4689) (n.b. this change is version gated and will only appear when the `version` configuration option is set to `Two`)
+
+### Changed
+
+- Renamed `fn_args_layout` configuration option to `fn_params_layout` [#4149](https://github.com/rust-lang/rustfmt/issues/4149). Note that `fn_args_layout` has only been soft deprecated: `fn_args_layout` will continue to work without issue, but rustfmt will display a warning to encourage users to switch to the new name
+
+### Added
+
+- New configuration option (`skip_macro_invocations`)[https://rust-lang.github.io/rustfmt/?version=master&search=#skip_macro_invocations] [#5347](https://github.com/rust-lang/rustfmt/pull/5347) that can be used to globally define a single enumerated list of macro calls that rustfmt should skip formatting. rustfmt [currently also supports this via a custom tool attribute](https://github.com/rust-lang/rustfmt#tips), however, these cannot be used in all contexts because [custom inner attributes are unstable](https://github.com/rust-lang/rust/issues/54726)
+
+### Misc
+
+- rustfmt now internally supports the ability to have both stable and unstable variants of a configuration option [#5378](https://github.com/rust-lang/rustfmt/issues/5378). This ability will allow the rustfmt team to make certain configuration options available on stable toolchains more quickly because we no longer have to wait for _every_ variant to be stable-ready before stabilizing _any_ variant. 
+
+### Install/Download Options
+- **rustup (nightly)** - nightly-2023-01-24
+- **GitHub Release Binaries** - [Release v1.5.2](https://github.com/rust-lang/rustfmt/releases/tag/v1.5.2)
+- **Build from source** - [Tag v1.5.2](https://github.com/rust-lang/rustfmt/tree/v1.5.2), see instructions for how to [install rustfmt from source][install-from-source]
+
 ## [1.5.1] 2022-06-24
 
 **N.B** A bug was introduced in v1.5.0/nightly-2022-06-15 which modified formatting. If you happened to run rustfmt over your code with one of those ~10 nightlies it's possible you may have seen formatting changes, and you may see additional changes after this fix since that bug has now been reverted.
@@ -840,7 +866,7 @@ from formatting an attribute #3665
 - Fix formatting of raw string literals #2983
 - Handle chain with try operators with spaces #2986
 - Use correct shape in Visual tuple rewriting #2987
-- Impove formatting of arguments with `visual_style = "Visual"` option #2988
+- Improve formatting of arguments with `visual_style = "Visual"` option #2988
 - Change `print_diff` to output the correct line number 992b179
 - Propagate errors about failing to rewrite a macro 6f318e3
 - Handle formatting of long function signature #3010
index 311df226da19dea273bd3b6680ea919f38b1eb33..24166d51c51fa2ed7279464a963e5e4642bc2a77 100644 (file)
@@ -476,7 +476,7 @@ checksum = "fc71d2faa173b74b232dedc235e3ee1696581bb132fc116fa3626d6151a1a8fb"
 
 [[package]]
 name = "rustfmt-config_proc_macro"
-version = "0.2.0"
+version = "0.3.0"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -485,7 +485,7 @@ dependencies = [
 
 [[package]]
 name = "rustfmt-nightly"
-version = "1.5.1"
+version = "1.5.2"
 dependencies = [
  "annotate-snippets",
  "anyhow",
index 7a4e02d69eddc05f7db59d35654d812b89031669..87ce59d0217e86be8751aa39a0f6a30f1ec3ae4a 100644 (file)
@@ -1,7 +1,7 @@
 [package]
 
 name = "rustfmt-nightly"
-version = "1.5.1"
+version = "1.5.2"
 description = "Tool to find and fix Rust formatting issues"
 repository = "https://github.com/rust-lang/rustfmt"
 readme = "README.md"
@@ -57,7 +57,7 @@ unicode-segmentation = "1.9"
 unicode-width = "0.1"
 unicode_categories = "0.1"
 
-rustfmt-config_proc_macro = { version = "0.2", path = "config_proc_macro" }
+rustfmt-config_proc_macro = { version = "0.3", path = "config_proc_macro" }
 
 # A noop dependency that changes in the Rust repository, it's a bit of a hack.
 # See the `src/tools/rustc-workspace-hack/README.md` file in `rust-lang/rust`
index 8b96b9d36892ae0494b72aeef42f409f34597e88..49e7e4e64892af081de2587366ba322c9f15a662 100644 (file)
@@ -1,6 +1,6 @@
 # Configuring Rustfmt
 
-Rustfmt is designed to be very configurable. You can create a TOML file called `rustfmt.toml` or `.rustfmt.toml`, place it in the project or any other parent directory and it will apply the options in that file. If none of these directories contain such a file, both your home directory and a directory called `rustfmt` in your [global config directory](https://docs.rs/dirs/1.0.4/dirs/fn.config_dir.html) (e.g. `.config/rustfmt/`) are checked as well.
+Rustfmt is designed to be very configurable. You can create a TOML file called `rustfmt.toml` or `.rustfmt.toml`, place it in the project or any other parent directory and it will apply the options in that file. If none of these directories contain such a file, both your home directory and a directory called `rustfmt` in your [global config directory](https://docs.rs/dirs/4.0.0/dirs/fn.config_dir.html) (e.g. `.config/rustfmt/`) are checked as well.
 
 A possible content of `rustfmt.toml` or `.rustfmt.toml` might look like this:
 
@@ -425,7 +425,7 @@ fn example() {
 
 ## `comment_width`
 
-Maximum length of comments. No effect unless`wrap_comments = true`.
+Maximum length of comments. No effect unless `wrap_comments = true`.
 
 - **Default value**: `80`
 - **Possible values**: any positive integer
@@ -589,7 +589,7 @@ doesn't get ignored when aligning.
 #### `0` (default):
 
 ```rust
-enum Bar {
+enum Foo {
     A = 0,
     Bb = 1,
     RandomLongVariantGoesHere = 10,
@@ -645,7 +645,8 @@ trailing whitespaces.
 
 ## `fn_args_layout`
 
-Control the layout of arguments in a function
+This option is deprecated and has been renamed to `fn_params_layout` to better communicate that
+it affects the layout of parameters in function signatures.
 
 - **Default value**: `"Tall"`
 - **Possible values**: `"Compressed"`, `"Tall"`, `"Vertical"`
@@ -753,6 +754,8 @@ trait Lorem {
 }
 ```
 
+See also [`fn_params_layout`](#fn_params_layout)
+
 ## `fn_call_width`
 
 Maximum width of the args of a function call before falling back to vertical formatting.
@@ -765,6 +768,117 @@ By default this option is set as a percentage of [`max_width`](#max_width) provi
 
 See also [`max_width`](#max_width) and [`use_small_heuristics`](#use_small_heuristics)
 
+## `fn_params_layout`
+
+Control the layout of parameters in function signatures.
+
+- **Default value**: `"Tall"`
+- **Possible values**: `"Compressed"`, `"Tall"`, `"Vertical"`
+- **Stable**: Yes
+
+#### `"Tall"` (default):
+
+```rust
+trait Lorem {
+    fn lorem(ipsum: Ipsum, dolor: Dolor, sit: Sit, amet: Amet);
+
+    fn lorem(ipsum: Ipsum, dolor: Dolor, sit: Sit, amet: Amet) {
+        // body
+    }
+
+    fn lorem(
+        ipsum: Ipsum,
+        dolor: Dolor,
+        sit: Sit,
+        amet: Amet,
+        consectetur: Consectetur,
+        adipiscing: Adipiscing,
+        elit: Elit,
+    );
+
+    fn lorem(
+        ipsum: Ipsum,
+        dolor: Dolor,
+        sit: Sit,
+        amet: Amet,
+        consectetur: Consectetur,
+        adipiscing: Adipiscing,
+        elit: Elit,
+    ) {
+        // body
+    }
+}
+```
+
+#### `"Compressed"`:
+
+```rust
+trait Lorem {
+    fn lorem(ipsum: Ipsum, dolor: Dolor, sit: Sit, amet: Amet);
+
+    fn lorem(ipsum: Ipsum, dolor: Dolor, sit: Sit, amet: Amet) {
+        // body
+    }
+
+    fn lorem(
+        ipsum: Ipsum, dolor: Dolor, sit: Sit, amet: Amet, consectetur: Consectetur,
+        adipiscing: Adipiscing, elit: Elit,
+    );
+
+    fn lorem(
+        ipsum: Ipsum, dolor: Dolor, sit: Sit, amet: Amet, consectetur: Consectetur,
+        adipiscing: Adipiscing, elit: Elit,
+    ) {
+        // body
+    }
+}
+```
+
+#### `"Vertical"`:
+
+```rust
+trait Lorem {
+    fn lorem(
+        ipsum: Ipsum,
+        dolor: Dolor,
+        sit: Sit,
+        amet: Amet,
+    );
+
+    fn lorem(
+        ipsum: Ipsum,
+        dolor: Dolor,
+        sit: Sit,
+        amet: Amet,
+    ) {
+        // body
+    }
+
+    fn lorem(
+        ipsum: Ipsum,
+        dolor: Dolor,
+        sit: Sit,
+        amet: Amet,
+        consectetur: Consectetur,
+        adipiscing: Adipiscing,
+        elit: Elit,
+    );
+
+    fn lorem(
+        ipsum: Ipsum,
+        dolor: Dolor,
+        sit: Sit,
+        amet: Amet,
+        consectetur: Consectetur,
+        adipiscing: Adipiscing,
+        elit: Elit,
+    ) {
+        // body
+    }
+}
+```
+
+
 ## `fn_single_line`
 
 Put single-expression functions on a single line
@@ -1014,6 +1128,62 @@ macro_rules! foo {
 
 See also [`format_macro_matchers`](#format_macro_matchers).
 
+## `skip_macro_invocations`
+
+Skip formatting the bodies of macro invocations with the following names.
+
+rustfmt will not format any macro invocation for macros with names set in this list.
+Including the special value "*" will prevent any macro invocations from being formatted.
+
+Note: This option does not have any impact on how rustfmt formats macro definitions.
+
+- **Default value**: `[]`
+- **Possible values**: a list of macro name idents, `["name_0", "name_1", ..., "*"]`
+- **Stable**: No (tracking issue: [#5346](https://github.com/rust-lang/rustfmt/issues/5346))
+
+#### `[]` (default):
+
+rustfmt will follow its standard approach to formatting macro invocations.
+
+No macro invocations will be skipped based on their name. More information about rustfmt's standard macro invocation formatting behavior can be found in [#5437](https://github.com/rust-lang/rustfmt/discussions/5437).
+
+```rust
+lorem!(
+    const _: u8 = 0;
+);
+
+ipsum!(
+    const _: u8 = 0;
+);
+```
+
+#### `["lorem"]`:
+
+The named macro invocations will be skipped.
+
+```rust
+lorem!(
+        const _: u8 = 0;
+);
+
+ipsum!(
+    const _: u8 = 0;
+);
+```
+
+#### `["*"]`:
+
+The special selector `*` will skip all macro invocations.
+
+```rust
+lorem!(
+        const _: u8 = 0;
+);
+
+ipsum!(
+        const _: u8 = 0;
+);
+```
 
 ## `format_strings`
 
@@ -1687,13 +1857,16 @@ pub enum Foo {}
 
 ## `imports_granularity`
 
-How imports should be grouped into `use` statements. Imports will be merged or split to the configured level of granularity.
+Controls how imports are structured in `use` statements. Imports will be merged or split to the configured level of granularity.
+
+Similar to other `import` related configuration options, this option operates within the bounds of user-defined groups of imports. See [`group_imports`](#group_imports) for more information on import groups.
+
+Note that rustfmt will not modify the granularity of imports containing comments if doing so could potentially lose or misplace said comments.
 
 - **Default value**: `Preserve`
 - **Possible values**: `Preserve`, `Crate`, `Module`, `Item`, `One`
 - **Stable**: No (tracking issue: [#4991](https://github.com/rust-lang/rustfmt/issues/4991))
 
-Note that rustfmt will not modify the granularity of imports containing comments if doing so could potentially lose or misplace said comments.
 
 #### `Preserve` (default):
 
index f763b5714ce2c746a43fc33b82fbc8a9c723b311..61abc87eec9ffffbb40b92d471ba65c24dad0412 100644 (file)
@@ -2,7 +2,7 @@ This document outlines processes regarding management of rustfmt.
 
 # Stabilising an Option
 
-In this Section, we describe how to stabilise an option of the rustfmt's configration.
+In this Section, we describe how to stabilise an option of the rustfmt's configuration.
 
 ## Conditions
 
index ef41017783feb6e44f576f3bc3e58b8a8bdfa1c3..69dae1fff7b4d8f373e342fc10ee2584ec1f1809 100755 (executable)
@@ -1,4 +1,5 @@
 set "RUSTFLAGS=-D warnings"
+set "RUSTFMT_CI=1"
 
 :: Print version information
 rustc -Vv || exit /b 1
index 8fa0f67b0d02184e63d299bfcf0befb7ee82ce9a..94991853263ce4bbb7c47815234d785763db660d 100755 (executable)
@@ -3,6 +3,7 @@
 set -euo pipefail
 
 export RUSTFLAGS="-D warnings"
+export RUSTFMT_CI=1
 
 # Print version information
 rustc -Vv
diff --git a/src/tools/rustfmt/ci/check_diff.sh b/src/tools/rustfmt/ci/check_diff.sh
new file mode 100755 (executable)
index 0000000..062c2dd
--- /dev/null
@@ -0,0 +1,199 @@
+#!/bin/bash
+
+function print_usage() {
+    echo "usage check_diff REMOTE_REPO FEATURE_BRANCH [COMMIT_HASH] [OPTIONAL_RUSTFMT_CONFIGS]"
+}
+
+if [ $# -le 1 ]; then
+    print_usage
+    exit 1
+fi
+
+REMOTE_REPO=$1
+FEATURE_BRANCH=$2
+OPTIONAL_COMMIT_HASH=$3
+OPTIONAL_RUSTFMT_CONFIGS=$4
+
+# OUTPUT array used to collect all the status of running diffs on various repos
+STATUSES=()
+
+# Clone a git repository and cd into it.
+#
+# Parameters:
+# $1: git clone url
+# $2: directory where the repo should be cloned
+function clone_repo() {
+    GIT_TERMINAL_PROMPT=0 git clone --quiet $1 --depth 1 $2 && cd $2
+}
+
+# Initialize Git submoduels for the repo.
+#
+# Parameters
+# $1: list of directories to initialize
+function init_submodules() {
+    git submodule update --init $1
+}
+
+# Run rusfmt with the --check flag to see if a diff is produced.
+#
+# Parameters:
+# $1: Path to a rustfmt binary
+# $2: Output file path for the diff
+# $3: Any additional configuration options to pass to rustfmt
+#
+# Globlas:
+# $OPTIONAL_RUSTFMT_CONFIGS: Optional configs passed to the script from $4
+function create_diff() {
+    local config;
+    if [ -z "$3" ]; then
+        config="--config=error_on_line_overflow=false,error_on_unformatted=false"
+    else
+        config="--config=error_on_line_overflow=false,error_on_unformatted=false,$OPTIONAL_RUSTFMT_CONFIGS"
+    fi
+
+    for i in `find . | grep "\.rs$"`
+    do
+        $1 --unstable-features --skip-children --check --color=always $config $i >> $2 2>/dev/null
+    done
+}
+
+# Run the master rustfmt binary and the feature branch binary in the current directory and compare the diffs
+#
+# Parameters
+# $1: Name of the repository (used for logging)
+#
+# Globlas:
+# $RUSFMT_BIN: Path to the rustfmt master binary. Created when running `compile_rustfmt`
+# $FEATURE_BIN: Path to the rustfmt feature binary. Created when running `compile_rustfmt`
+# $OPTIONAL_RUSTFMT_CONFIGS: Optional configs passed to the script from $4
+function check_diff() {
+    echo "running rustfmt (master) on $1"
+    create_diff $RUSFMT_BIN rustfmt_diff.txt
+
+    echo "running rustfmt (feature) on $1"
+    create_diff $FEATURE_BIN feature_diff.txt $OPTIONAL_RUSTFMT_CONFIGS
+
+    echo "checking diff"
+    local diff;
+    # we don't add color to the diff since we added color when running rustfmt --check.
+    # tail -n + 6 removes the git diff header info
+    # cut -c 2- removes the leading diff characters("+","-"," ") from running git diff.
+    # Again, the diff output we care about was already added when we ran rustfmt --check
+    diff=$(
+        git --no-pager diff --color=never \
+        --unified=0 --no-index rustfmt_diff.txt feature_diff.txt 2>&1 | tail -n +6 | cut -c 2-
+    )
+
+    if [ -z "$diff" ]; then
+        echo "no diff detected between rustfmt and the feture branch"
+        return 0
+    else
+        echo "$diff"
+        return 1
+    fi
+}
+
+# Compiles and produces two rustfmt binaries.
+# One for the current master, and another for the feature branch
+#
+# Parameters:
+# $1: Directory where rustfmt will be cloned
+#
+# Globlas:
+# $REMOTE_REPO: Clone URL to the rustfmt fork that we want to test
+# $FEATURE_BRANCH: Name of the feature branch
+# $OPTIONAL_COMMIT_HASH: Optional commit hash that will be checked out if provided
+function compile_rustfmt() {
+    RUSTFMT_REPO="https://github.com/rust-lang/rustfmt.git"
+    clone_repo $RUSTFMT_REPO $1
+    git remote add feature $REMOTE_REPO
+    git fetch feature $FEATURE_BRANCH
+
+    cargo build --release --bin rustfmt && cp target/release/rustfmt $1/rustfmt
+    if [ -z "$OPTIONAL_COMMIT_HASH" ]; then
+        git switch $FEATURE_BRANCH
+    else
+        git switch $OPTIONAL_COMMIT_HASH --detach
+    fi
+    cargo build --release --bin rustfmt && cp target/release/rustfmt $1/feature_rustfmt
+    RUSFMT_BIN=$1/rustfmt
+    FEATURE_BIN=$1/feature_rustfmt
+}
+
+# Check the diff for running rustfmt and the feature branch on all the .rs files in the repo.
+#
+# Parameters
+# $1: Clone URL for the repo
+# $2: Name of the repo (mostly used for logging)
+# $3: Path to any submodules that should be initialized
+function check_repo() {
+    WORKDIR=$(pwd)
+    REPO_URL=$1
+    REPO_NAME=$2
+    SUBMODULES=$3
+
+    local tmp_dir;
+    tmp_dir=$(mktemp -d -t $REPO_NAME-XXXXXXXX)
+    clone_repo $REPO_URL $tmp_dir
+
+    if [ ! -z "$SUBMODULES" ]; then
+        init_submodules $SUBMODULES
+    fi
+
+    check_diff $REPO_NAME
+    # append the status of running `check_diff` to the STATUSES array
+    STATUSES+=($?)
+
+    echo "removing tmp_dir $tmp_dir"
+    rm -rf $tmp_dir
+    cd $WORKDIR
+}
+
+function main() {
+    tmp_dir=$(mktemp -d -t rustfmt-XXXXXXXX)
+    echo Created tmp_dir $tmp_dir
+
+    compile_rustfmt $tmp_dir
+
+    # run checks
+    check_repo "https://github.com/rust-lang/rust.git" rust-lang-rust
+    check_repo "https://github.com/rust-lang/cargo.git" cargo
+    check_repo "https://github.com/rust-lang/miri.git" miri
+    check_repo "https://github.com/rust-lang/rust-analyzer.git" rust-analyzer
+    check_repo "https://github.com/bitflags/bitflags.git" bitflags
+    check_repo "https://github.com/rust-lang/log.git" log
+    check_repo "https://github.com/rust-lang/mdBook.git" mdBook
+    check_repo "https://github.com/rust-lang/packed_simd.git" packed_simd
+    check_repo "https://github.com/rust-lang/rust-semverver.git" check_repo
+    check_repo "https://github.com/Stebalien/tempfile.git" tempfile
+    check_repo "https://github.com/rust-lang/futures-rs.git" futures-rs
+    check_repo "https://github.com/dtolnay/anyhow.git" anyhow
+    check_repo "https://github.com/dtolnay/thiserror.git" thiserror
+    check_repo "https://github.com/dtolnay/syn.git" syn
+    check_repo "https://github.com/serde-rs/serde.git" serde
+    check_repo "https://github.com/rust-lang/rustlings.git" rustlings
+    check_repo "https://github.com/rust-lang/rustup.git" rustup
+    check_repo "https://github.com/SergioBenitez/Rocket.git" Rocket
+    check_repo "https://github.com/rustls/rustls.git" rustls
+    check_repo "https://github.com/rust-lang/rust-bindgen.git" rust-bindgen
+    check_repo "https://github.com/hyperium/hyper.git" hyper
+    check_repo "https://github.com/actix/actix.git" actix
+    check_repo "https://github.com/denoland/deno.git" denoland_deno
+
+    # cleanup temp dir
+    echo removing tmp_dir $tmp_dir
+    rm -rf $tmp_dir
+
+    # figure out the exit code
+    for status in ${STATUSES[@]}
+    do
+        if [ $status -eq 1 ]; then
+            echo "formatting diff found 💔"
+            return 1
+        fi
+    done
+
+    echo "no diff found 😊"
+}
+
+main
index 562d5d70c70ba63a5dbfcfc3d4709897efed615a..19d502bc5c7bdd854f6c187b71ce2f0213f631de 100755 (executable)
@@ -91,14 +91,28 @@ case ${INTEGRATION} in
         cd -
         ;;
     crater)
-        git clone --depth=1 https://github.com/rust-lang-nursery/${INTEGRATION}.git
+        git clone --depth=1 https://github.com/rust-lang/${INTEGRATION}.git
         cd ${INTEGRATION}
         show_head
         check_fmt_with_lib_tests
         cd -
         ;;
+    bitflags)
+        git clone --depth=1 https://github.com/bitflags/${INTEGRATION}.git
+        cd ${INTEGRATION}
+        show_head
+        check_fmt_with_all_tests
+        cd -
+        ;;
+    error-chain | tempdir)
+        git clone --depth=1 https://github.com/rust-lang-deprecated/${INTEGRATION}.git
+        cd ${INTEGRATION}
+        show_head
+        check_fmt_with_all_tests
+        cd -
+        ;;
     *)
-        git clone --depth=1 https://github.com/rust-lang-nursery/${INTEGRATION}.git
+        git clone --depth=1 https://github.com/rust-lang/${INTEGRATION}.git
         cd ${INTEGRATION}
         show_head
         check_fmt_with_all_tests
index ecf561f28fb6aa5e64cffedfdefd2a146e61b1d5..49f2f72a8d2196323aeefce78a22fdd8b0afd80d 100644 (file)
@@ -22,7 +22,7 @@ dependencies = [
 
 [[package]]
 name = "rustfmt-config_proc_macro"
-version = "0.2.0"
+version = "0.3.0"
 dependencies = [
  "proc-macro2",
  "quote",
index a41b3a5e6bf8846a0dcdc9b89f4d3b5313095904..d10d0469cc401ffe3564c93f7eb1b2033cf31bb9 100644 (file)
@@ -1,6 +1,6 @@
 [package]
 name = "rustfmt-config_proc_macro"
-version = "0.2.0"
+version = "0.3.0"
 edition = "2018"
 description = "A collection of procedural macros for rustfmt"
 license = "Apache-2.0/MIT"
index 0baba046f9e9149ecaddd32786dfac65a0fbc58b..dd18ff572cb1cd28daee3d0925f459557ae202fd 100644 (file)
@@ -1,8 +1,10 @@
 //! This module provides utilities for handling attributes on variants
-//! of `config_type` enum. Currently there are two types of attributes
-//! that could appear on the variants of `config_type` enum: `doc_hint`
-//! and `value`. Both comes in the form of name-value pair whose value
-//! is string literal.
+//! of `config_type` enum. Currently there are the following attributes
+//! that could appear on the variants of `config_type` enum:
+//!
+//! - `doc_hint`: name-value pair whose value is string literal
+//! - `value`: name-value pair whose value is string literal
+//! - `unstable_variant`: name only
 
 /// Returns the value of the first `doc_hint` attribute in the given slice or
 /// `None` if `doc_hint` attribute is not available.
@@ -27,6 +29,11 @@ pub fn find_config_value(attrs: &[syn::Attribute]) -> Option<String> {
     attrs.iter().filter_map(config_value).next()
 }
 
+/// Returns `true` if the there is at least one `unstable` attribute in the given slice.
+pub fn any_unstable_variant(attrs: &[syn::Attribute]) -> bool {
+    attrs.iter().any(is_unstable_variant)
+}
+
 /// Returns a string literal value if the given attribute is `value`
 /// attribute or `None` otherwise.
 pub fn config_value(attr: &syn::Attribute) -> Option<String> {
@@ -38,6 +45,11 @@ pub fn is_config_value(attr: &syn::Attribute) -> bool {
     is_attr_name_value(attr, "value")
 }
 
+/// Returns `true` if the given attribute is an `unstable` attribute.
+pub fn is_unstable_variant(attr: &syn::Attribute) -> bool {
+    is_attr_path(attr, "unstable_variant")
+}
+
 fn is_attr_name_value(attr: &syn::Attribute, name: &str) -> bool {
     attr.parse_meta().ok().map_or(false, |meta| match meta {
         syn::Meta::NameValue(syn::MetaNameValue { ref path, .. }) if path.is_ident(name) => true,
@@ -45,6 +57,13 @@ fn is_attr_name_value(attr: &syn::Attribute, name: &str) -> bool {
     })
 }
 
+fn is_attr_path(attr: &syn::Attribute, name: &str) -> bool {
+    attr.parse_meta().ok().map_or(false, |meta| match meta {
+        syn::Meta::Path(path) if path.is_ident(name) => true,
+        _ => false,
+    })
+}
+
 fn get_name_value_str_lit(attr: &syn::Attribute, name: &str) -> Option<String> {
     attr.parse_meta().ok().and_then(|meta| match meta {
         syn::Meta::NameValue(syn::MetaNameValue {
index dcee77a8549c5b9cf9beacd47663cb39d177c4ce..731a7ea06077bf5dc7d677b3295310b2bbd7b942 100644 (file)
@@ -1,5 +1,6 @@
 use proc_macro2::TokenStream;
-use quote::quote;
+use quote::{quote, quote_spanned};
+use syn::spanned::Spanned;
 
 use crate::attrs::*;
 use crate::utils::*;
@@ -47,12 +48,23 @@ fn process_variant(variant: &syn::Variant) -> TokenStream {
     let metas = variant
         .attrs
         .iter()
-        .filter(|attr| !is_doc_hint(attr) && !is_config_value(attr));
+        .filter(|attr| !is_doc_hint(attr) && !is_config_value(attr) && !is_unstable_variant(attr));
     let attrs = fold_quote(metas, |meta| quote!(#meta));
     let syn::Variant { ident, fields, .. } = variant;
     quote!(#attrs #ident #fields)
 }
 
+/// Return the correct syntax to pattern match on the enum variant, discarding all
+/// internal field data.
+fn fields_in_variant(variant: &syn::Variant) -> TokenStream {
+    // With thanks to https://stackoverflow.com/a/65182902
+    match &variant.fields {
+        syn::Fields::Unnamed(_) => quote_spanned! { variant.span() => (..) },
+        syn::Fields::Unit => quote_spanned! { variant.span() => },
+        syn::Fields::Named(_) => quote_spanned! { variant.span() => {..} },
+    }
+}
+
 fn impl_doc_hint(ident: &syn::Ident, variants: &Variants) -> TokenStream {
     let doc_hint = variants
         .iter()
@@ -60,12 +72,26 @@ fn impl_doc_hint(ident: &syn::Ident, variants: &Variants) -> TokenStream {
         .collect::<Vec<_>>()
         .join("|");
     let doc_hint = format!("[{}]", doc_hint);
+
+    let variant_stables = variants
+        .iter()
+        .map(|v| (&v.ident, fields_in_variant(&v), !unstable_of_variant(v)));
+    let match_patterns = fold_quote(variant_stables, |(v, fields, stable)| {
+        quote! {
+            #ident::#v #fields => #stable,
+        }
+    });
     quote! {
         use crate::config::ConfigType;
         impl ConfigType for #ident {
             fn doc_hint() -> String {
                 #doc_hint.to_owned()
             }
+            fn stable_variant(&self) -> bool {
+                match self {
+                    #match_patterns
+                }
+            }
         }
     }
 }
@@ -123,13 +149,21 @@ fn from_str(s: &str) -> Result<Self, Self::Err> {
 }
 
 fn doc_hint_of_variant(variant: &syn::Variant) -> String {
-    find_doc_hint(&variant.attrs).unwrap_or(variant.ident.to_string())
+    let mut text = find_doc_hint(&variant.attrs).unwrap_or(variant.ident.to_string());
+    if unstable_of_variant(&variant) {
+        text.push_str(" (unstable)")
+    };
+    text
 }
 
 fn config_value_of_variant(variant: &syn::Variant) -> String {
     find_config_value(&variant.attrs).unwrap_or(variant.ident.to_string())
 }
 
+fn unstable_of_variant(variant: &syn::Variant) -> bool {
+    any_unstable_variant(&variant.attrs)
+}
+
 fn impl_serde(ident: &syn::Ident, variants: &Variants) -> TokenStream {
     let arms = fold_quote(variants.iter(), |v| {
         let v_ident = &v.ident;
index e772c53f42361f94131e0e67294b107ae532a0cd..0c54c132c97d8f3abb79a0126bfdd5d80af8c35d 100644 (file)
@@ -69,3 +69,16 @@ pub fn stable_only_test(_args: TokenStream, input: TokenStream) -> TokenStream {
         TokenStream::from_str("").unwrap()
     }
 }
+
+/// Used to conditionally output the TokenStream for tests that should be run as part of rustfmts
+/// test suite, but should be ignored when running in the rust-lang/rust test suite.
+#[proc_macro_attribute]
+pub fn rustfmt_only_ci_test(_args: TokenStream, input: TokenStream) -> TokenStream {
+    if option_env!("RUSTFMT_CI").is_some() {
+        input
+    } else {
+        let mut token_stream = TokenStream::from_str("#[ignore]").unwrap();
+        token_stream.extend(input);
+        token_stream
+    }
+}
index 940a8a0c251e45ea2fc65b1b3edbab9aa8244884..c8a83e39c9efc656d1d411de343a8fdb0aa23cbb 100644 (file)
@@ -1,6 +1,7 @@
 pub mod config {
     pub trait ConfigType: Sized {
         fn doc_hint() -> String;
+        fn stable_variant(&self) -> bool;
     }
 }
 
index 2640a9e0ecc286cd9c0e6e020e1207ffe17bf8e1..22283b3d62002019b88b0a47441cb7d6a0a874d1 100644 (file)
@@ -1,3 +1,3 @@
 [toolchain]
-channel = "nightly-2022-06-21"
-components = ["rustc-dev"]
+channel = "nightly-2023-01-24"
+components = ["llvm-tools", "rustc-dev"]
index c503eeeb9b3b950e387d7b8b0e6a82dcd40a226b..5648e1254ed7cd14d947a117d071bb7572fbdd61 100644 (file)
@@ -336,7 +336,7 @@ fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String>
         } else {
             let should_skip = self
                 .ident()
-                .map(|s| context.skip_context.skip_attribute(s.name.as_str()))
+                .map(|s| context.skip_context.attributes.skip(s.name.as_str()))
                 .unwrap_or(false);
             let prefix = attr_prefix(self);
 
@@ -390,7 +390,7 @@ fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String>
 
         // Determine if the source text is annotated with `#[rustfmt::skip::attributes(derive)]`
         // or `#![rustfmt::skip::attributes(derive)]`
-        let skip_derives = context.skip_context.skip_attribute("derive");
+        let skip_derives = context.skip_context.attributes.skip("derive");
 
         // This is not just a simple map because we need to handle doc comments
         // (where we take as many doc comment attributes as possible) and possibly
index 8e871e61f26837c5b2ed21cd1fd4348ec60e4cbd..be64559e8774593abd5ab9c93a6b8f5c68a39f13 100644 (file)
@@ -136,7 +136,7 @@ fn make_opts() -> Options {
         "l",
         "files-with-diff",
         "Prints the names of mismatched files that were formatted. Prints the names of \
-         files that would be formated when used with `--check` mode. ",
+         files that would be formatted when used with `--check` mode. ",
     );
     opts.optmulti(
         "",
index 9031d29b45f7ff3e7b3f3a4c0b58a8a465ae9ebf..2b714b68df00e39f97a4324b1f0764e57449face 100644 (file)
@@ -198,12 +198,10 @@ fn convert_message_format_to_rustfmt_args(
             Ok(())
         }
         "human" => Ok(()),
-        _ => {
-            return Err(format!(
-                "invalid --message-format value: {}. Allowed values are: short|json|human",
-                message_format
-            ));
-        }
+        _ => Err(format!(
+            "invalid --message-format value: {}. Allowed values are: short|json|human",
+            message_format
+        )),
     }
 }
 
@@ -215,7 +213,7 @@ fn print_usage_to_stderr(reason: &str) {
         .expect("failed to write to stderr");
 }
 
-#[derive(Debug, Clone, Copy, PartialEq)]
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 pub enum Verbosity {
     Verbose,
     Normal,
index 56e52fbabb68b4876308b011d955a6de71c78c49..696326e4f94061acf918fabcc62d355851e03cc3 100644 (file)
@@ -70,9 +70,9 @@ fn mandatory_separator() {
             .is_err()
     );
     assert!(
-        !Opts::command()
+        Opts::command()
             .try_get_matches_from(&["test", "--", "--emit"])
-            .is_err()
+            .is_ok()
     );
 }
 
index a1a73cf4bd570f2ee495766e207e2e7935487773..39b8d6878097d369df7f8ab52f3be00d77a2312d 100644 (file)
 use crate::shape::Shape;
 use crate::source_map::SpanUtils;
 use crate::utils::{
-    self, first_line_width, last_line_extendable, last_line_width, mk_sp, rewrite_ident,
-    trimmed_last_line_width, wrap_str,
+    self, filtered_str_fits, first_line_width, last_line_extendable, last_line_width, mk_sp,
+    rewrite_ident, trimmed_last_line_width, wrap_str,
 };
 
+/// Provides the original input contents from the span
+/// of a chain element with trailing spaces trimmed.
+fn format_overflow_style(span: Span, context: &RewriteContext<'_>) -> Option<String> {
+    context.snippet_provider.span_to_snippet(span).map(|s| {
+        s.lines()
+            .map(|l| l.trim_end())
+            .collect::<Vec<_>>()
+            .join("\n")
+    })
+}
+
+fn format_chain_item(
+    item: &ChainItem,
+    context: &RewriteContext<'_>,
+    rewrite_shape: Shape,
+    allow_overflow: bool,
+) -> Option<String> {
+    if allow_overflow {
+        item.rewrite(context, rewrite_shape)
+            .or_else(|| format_overflow_style(item.span, context))
+    } else {
+        item.rewrite(context, rewrite_shape)
+    }
+}
+
+fn get_block_child_shape(
+    prev_ends_with_block: bool,
+    context: &RewriteContext<'_>,
+    shape: Shape,
+) -> Shape {
+    if prev_ends_with_block {
+        shape.block_indent(0)
+    } else {
+        shape.block_indent(context.config.tab_spaces())
+    }
+    .with_max_width(context.config)
+}
+
+fn get_visual_style_child_shape(
+    context: &RewriteContext<'_>,
+    shape: Shape,
+    offset: usize,
+    parent_overflowing: bool,
+) -> Option<Shape> {
+    if !parent_overflowing {
+        shape
+            .with_max_width(context.config)
+            .offset_left(offset)
+            .map(|s| s.visual_indent(0))
+    } else {
+        Some(shape.visual_indent(offset))
+    }
+}
+
 pub(crate) fn rewrite_chain(
     expr: &ast::Expr,
     context: &RewriteContext<'_>,
@@ -496,6 +550,8 @@ struct ChainFormatterShared<'a> {
     // The number of children in the chain. This is not equal to `self.children.len()`
     // because `self.children` will change size as we process the chain.
     child_count: usize,
+    // Whether elements are allowed to overflow past the max_width limit
+    allow_overflow: bool,
 }
 
 impl<'a> ChainFormatterShared<'a> {
@@ -505,6 +561,8 @@ fn new(chain: &'a Chain) -> ChainFormatterShared<'a> {
             rewrites: Vec::with_capacity(chain.children.len() + 1),
             fits_single_line: false,
             child_count: chain.children.len(),
+            // TODO(calebcartwright)
+            allow_overflow: false,
         }
     }
 
@@ -517,6 +575,14 @@ fn pure_root(&mut self) -> Option<String> {
         }
     }
 
+    fn format_children(&mut self, context: &RewriteContext<'_>, child_shape: Shape) -> Option<()> {
+        for item in &self.children[..self.children.len() - 1] {
+            let rewrite = format_chain_item(item, context, child_shape, self.allow_overflow)?;
+            self.rewrites.push(rewrite);
+        }
+        Some(())
+    }
+
     // Rewrite the last child. The last child of a chain requires special treatment. We need to
     // know whether 'overflowing' the last child make a better formatting:
     //
@@ -729,22 +795,12 @@ fn format_root(
     }
 
     fn child_shape(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<Shape> {
-        Some(
-            if self.root_ends_with_block {
-                shape.block_indent(0)
-            } else {
-                shape.block_indent(context.config.tab_spaces())
-            }
-            .with_max_width(context.config),
-        )
+        let block_end = self.root_ends_with_block;
+        Some(get_block_child_shape(block_end, context, shape))
     }
 
     fn format_children(&mut self, context: &RewriteContext<'_>, child_shape: Shape) -> Option<()> {
-        for item in &self.shared.children[..self.shared.children.len() - 1] {
-            let rewrite = item.rewrite(context, child_shape)?;
-            self.shared.rewrites.push(rewrite);
-        }
-        Some(())
+        self.shared.format_children(context, child_shape)
     }
 
     fn format_last_child(
@@ -808,15 +864,14 @@ fn format_root(
                 .visual_indent(self.offset)
                 .sub_width(self.offset)?;
             let rewrite = item.rewrite(context, child_shape)?;
-            match wrap_str(rewrite, context.config.max_width(), shape) {
-                Some(rewrite) => root_rewrite.push_str(&rewrite),
-                None => {
-                    // We couldn't fit in at the visual indent, try the last
-                    // indent.
-                    let rewrite = item.rewrite(context, parent_shape)?;
-                    root_rewrite.push_str(&rewrite);
-                    self.offset = 0;
-                }
+            if filtered_str_fits(&rewrite, context.config.max_width(), shape) {
+                root_rewrite.push_str(&rewrite);
+            } else {
+                // We couldn't fit in at the visual indent, try the last
+                // indent.
+                let rewrite = item.rewrite(context, parent_shape)?;
+                root_rewrite.push_str(&rewrite);
+                self.offset = 0;
             }
 
             self.shared.children = &self.shared.children[1..];
@@ -827,18 +882,17 @@ fn format_root(
     }
 
     fn child_shape(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<Shape> {
-        shape
-            .with_max_width(context.config)
-            .offset_left(self.offset)
-            .map(|s| s.visual_indent(0))
+        get_visual_style_child_shape(
+            context,
+            shape,
+            self.offset,
+            // TODO(calebcartwright): self.shared.permissibly_overflowing_parent,
+            false,
+        )
     }
 
     fn format_children(&mut self, context: &RewriteContext<'_>, child_shape: Shape) -> Option<()> {
-        for item in &self.shared.children[..self.shared.children.len() - 1] {
-            let rewrite = item.rewrite(context, child_shape)?;
-            self.shared.rewrites.push(rewrite);
-        }
-        Some(())
+        self.shared.format_children(context, child_shape)
     }
 
     fn format_last_child(
index c5e61658ad1ed19106c4f9860b994f8588fe0e90..54ca7676dfc8bd9c7f1a01ef7c4a94d8c6f1bc4b 100644 (file)
@@ -1,4 +1,5 @@
 use crate::config::file_lines::FileLines;
+use crate::config::macro_names::MacroSelectors;
 use crate::config::options::{IgnoreList, WidthHeuristics};
 
 /// Trait for types that can be used in `Config`.
@@ -6,6 +7,14 @@ pub(crate) trait ConfigType: Sized {
     /// Returns hint text for use in `Config::print_docs()`. For enum types, this is a
     /// pipe-separated list of variants; for other types it returns `<type>`.
     fn doc_hint() -> String;
+
+    /// Return `true` if the variant (i.e. value of this type) is stable.
+    ///
+    /// By default, return true for all values. Enums annotated with `#[config_type]`
+    /// are automatically implemented, based on the `#[unstable_variant]` annotation.
+    fn stable_variant(&self) -> bool {
+        true
+    }
 }
 
 impl ConfigType for bool {
@@ -38,6 +47,12 @@ fn doc_hint() -> String {
     }
 }
 
+impl ConfigType for MacroSelectors {
+    fn doc_hint() -> String {
+        String::from("[<string>, ...]")
+    }
+}
+
 impl ConfigType for WidthHeuristics {
     fn doc_hint() -> String {
         String::new()
@@ -51,6 +66,13 @@ fn doc_hint() -> String {
 }
 
 macro_rules! create_config {
+    // Options passed in to the macro.
+    //
+    // - $i: the ident name of the option
+    // - $ty: the type of the option value
+    // - $def: the default value of the option
+    // - $stb: true if the option is stable
+    // - $dstring: description of the option
     ($($i:ident: $ty:ty, $def:expr, $stb:expr, $( $dstring:expr ),+ );+ $(;)*) => (
         #[cfg(test)]
         use std::collections::HashSet;
@@ -61,9 +83,12 @@ macro_rules! create_config {
         #[derive(Clone)]
         #[allow(unreachable_pub)]
         pub struct Config {
-            // For each config item, we store a bool indicating whether it has
-            // been accessed and the value, and a bool whether the option was
-            // manually initialised, or taken from the default,
+            // For each config item, we store:
+            //
+            // - 0: true if the value has been access
+            // - 1: true if the option was manually initialized
+            // - 2: the option value
+            // - 3: true if the option is unstable
             $($i: (Cell<bool>, bool, $ty, bool)),+
         }
 
@@ -102,6 +127,7 @@ pub fn $i(&mut self, value: $ty) {
                     | "array_width"
                     | "chain_width" => self.0.set_heuristics(),
                     "merge_imports" => self.0.set_merge_imports(),
+                    "fn_args_layout" => self.0.set_fn_args_layout(),
                     &_ => (),
                 }
             }
@@ -143,24 +169,20 @@ pub fn was_set(&self) -> ConfigWasSet<'_> {
 
             fn fill_from_parsed_config(mut self, parsed: PartialConfig, dir: &Path) -> Config {
             $(
-                if let Some(val) = parsed.$i {
-                    if self.$i.3 {
+                if let Some(option_value) = parsed.$i {
+                    let option_stable = self.$i.3;
+                    if $crate::config::config_type::is_stable_option_and_value(
+                        stringify!($i), option_stable, &option_value
+                    ) {
                         self.$i.1 = true;
-                        self.$i.2 = val;
-                    } else {
-                        if crate::is_nightly_channel!() {
-                            self.$i.1 = true;
-                            self.$i.2 = val;
-                        } else {
-                            eprintln!("Warning: can't set `{} = {:?}`, unstable features are only \
-                                       available in nightly channel.", stringify!($i), val);
-                        }
+                        self.$i.2 = option_value;
                     }
                 }
             )+
                 self.set_heuristics();
                 self.set_ignore(dir);
                 self.set_merge_imports();
+                self.set_fn_args_layout();
                 self
             }
 
@@ -221,12 +243,22 @@ pub fn override_value(&mut self, key: &str, val: &str)
                 match key {
                     $(
                         stringify!($i) => {
-                            self.$i.1 = true;
-                            self.$i.2 = val.parse::<$ty>()
+                            let option_value = val.parse::<$ty>()
                                 .expect(&format!("Failed to parse override for {} (\"{}\") as a {}",
                                                  stringify!($i),
                                                  val,
                                                  stringify!($ty)));
+
+                            // Users are currently allowed to set unstable
+                            // options/variants via the `--config` options override.
+                            //
+                            // There is ongoing discussion about how to move forward here:
+                            // https://github.com/rust-lang/rustfmt/pull/5379
+                            //
+                            // For now, do not validate whether the option or value is stable,
+                            // just always set it.
+                            self.$i.1 = true;
+                            self.$i.2 = option_value;
                         }
                     )+
                     _ => panic!("Unknown config key in override: {}", key)
@@ -243,14 +275,21 @@ pub fn override_value(&mut self, key: &str, val: &str)
                     | "array_width"
                     | "chain_width" => self.set_heuristics(),
                     "merge_imports" => self.set_merge_imports(),
+                    "fn_args_layout" => self.set_fn_args_layout(),
                     &_ => (),
                 }
             }
 
             #[allow(unreachable_pub)]
             pub fn is_hidden_option(name: &str) -> bool {
-                const HIDE_OPTIONS: [&str; 5] =
-                    ["verbose", "verbose_diff", "file_lines", "width_heuristics", "merge_imports"];
+                const HIDE_OPTIONS: [&str; 6] = [
+                    "verbose",
+                    "verbose_diff",
+                    "file_lines",
+                    "width_heuristics",
+                    "merge_imports",
+                    "fn_args_layout"
+                ];
                 HIDE_OPTIONS.contains(&name)
             }
 
@@ -400,6 +439,18 @@ fn set_merge_imports(&mut self) {
                 }
             }
 
+            fn set_fn_args_layout(&mut self) {
+                if self.was_set().fn_args_layout() {
+                    eprintln!(
+                        "Warning: the `fn_args_layout` option is deprecated. \
+                        Use `fn_params_layout`. instead"
+                    );
+                    if !self.was_set().fn_params_layout() {
+                        self.fn_params_layout.2 = self.fn_args_layout();
+                    }
+                }
+            }
+
             #[allow(unreachable_pub)]
             /// Returns `true` if the config key was explicitly set and is the default value.
             pub fn is_default(&self, key: &str) -> bool {
@@ -424,3 +475,38 @@ fn default() -> Config {
         }
     )
 }
+
+pub(crate) fn is_stable_option_and_value<T>(
+    option_name: &str,
+    option_stable: bool,
+    option_value: &T,
+) -> bool
+where
+    T: PartialEq + std::fmt::Debug + ConfigType,
+{
+    let nightly = crate::is_nightly_channel!();
+    let variant_stable = option_value.stable_variant();
+    match (nightly, option_stable, variant_stable) {
+        // Stable with an unstable option
+        (false, false, _) => {
+            eprintln!(
+                "Warning: can't set `{} = {:?}`, unstable features are only \
+                       available in nightly channel.",
+                option_name, option_value
+            );
+            false
+        }
+        // Stable with a stable option, but an unstable variant
+        (false, true, false) => {
+            eprintln!(
+                "Warning: can't set `{} = {:?}`, unstable variants are only \
+                       available in nightly channel.",
+                option_name, option_value
+            );
+            false
+        }
+        // Nightly: everything allowed
+        // Stable with stable option and variant: allowed
+        (true, _, _) | (false, true, true) => true,
+    }
+}
diff --git a/src/tools/rustfmt/src/config/macro_names.rs b/src/tools/rustfmt/src/config/macro_names.rs
new file mode 100644 (file)
index 0000000..26ad78d
--- /dev/null
@@ -0,0 +1,118 @@
+//! This module contains types and functions to support formatting specific macros.
+
+use itertools::Itertools;
+use std::{fmt, str};
+
+use serde::{Deserialize, Serialize};
+use serde_json as json;
+use thiserror::Error;
+
+/// Defines the name of a macro.
+#[derive(Clone, Debug, Eq, PartialEq, Hash, Ord, PartialOrd, Deserialize, Serialize)]
+pub struct MacroName(String);
+
+impl MacroName {
+    pub fn new(other: String) -> Self {
+        Self(other)
+    }
+}
+
+impl fmt::Display for MacroName {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        self.0.fmt(f)
+    }
+}
+
+impl From<MacroName> for String {
+    fn from(other: MacroName) -> Self {
+        other.0
+    }
+}
+
+/// Defines a selector to match against a macro.
+#[derive(Clone, Debug, Eq, PartialEq, Hash, Ord, PartialOrd, Deserialize, Serialize)]
+pub enum MacroSelector {
+    Name(MacroName),
+    All,
+}
+
+impl fmt::Display for MacroSelector {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        match self {
+            Self::Name(name) => name.fmt(f),
+            Self::All => write!(f, "*"),
+        }
+    }
+}
+
+impl str::FromStr for MacroSelector {
+    type Err = std::convert::Infallible;
+
+    fn from_str(s: &str) -> Result<Self, Self::Err> {
+        Ok(match s {
+            "*" => MacroSelector::All,
+            name => MacroSelector::Name(MacroName(name.to_owned())),
+        })
+    }
+}
+
+/// A set of macro selectors.
+#[derive(Clone, Debug, Default, PartialEq, Deserialize, Serialize)]
+pub struct MacroSelectors(pub Vec<MacroSelector>);
+
+impl fmt::Display for MacroSelectors {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        write!(f, "{}", self.0.iter().format(", "))
+    }
+}
+
+#[derive(Error, Debug)]
+pub enum MacroSelectorsError {
+    #[error("{0}")]
+    Json(json::Error),
+}
+
+// This impl is needed for `Config::override_value` to work for use in tests.
+impl str::FromStr for MacroSelectors {
+    type Err = MacroSelectorsError;
+
+    fn from_str(s: &str) -> Result<Self, Self::Err> {
+        let raw: Vec<&str> = json::from_str(s).map_err(MacroSelectorsError::Json)?;
+        Ok(Self(
+            raw.into_iter()
+                .map(|raw| {
+                    MacroSelector::from_str(raw).expect("MacroSelector from_str is infallible")
+                })
+                .collect(),
+        ))
+    }
+}
+
+#[cfg(test)]
+mod test {
+    use super::*;
+    use std::str::FromStr;
+
+    #[test]
+    fn macro_names_from_str() {
+        let macro_names = MacroSelectors::from_str(r#"["foo", "*", "bar"]"#).unwrap();
+        assert_eq!(
+            macro_names,
+            MacroSelectors(
+                [
+                    MacroSelector::Name(MacroName("foo".to_owned())),
+                    MacroSelector::All,
+                    MacroSelector::Name(MacroName("bar".to_owned()))
+                ]
+                .into_iter()
+                .collect()
+            )
+        );
+    }
+
+    #[test]
+    fn macro_names_display() {
+        let macro_names = MacroSelectors::from_str(r#"["foo", "*", "bar"]"#).unwrap();
+        assert_eq!(format!("{}", macro_names), "foo, *, bar");
+    }
+}
index f49c18d3a4603a9804168664629c314181d7838f..14f27f3f8b692ba14c47c5be138880a625ae5009 100644 (file)
 #[allow(unreachable_pub)]
 pub use crate::config::lists::*;
 #[allow(unreachable_pub)]
+pub use crate::config::macro_names::{MacroSelector, MacroSelectors};
+#[allow(unreachable_pub)]
 pub use crate::config::options::*;
 
 #[macro_use]
 pub(crate) mod config_type;
 #[macro_use]
+#[allow(unreachable_pub)]
 pub(crate) mod options;
 
 pub(crate) mod file_lines;
+#[allow(unreachable_pub)]
 pub(crate) mod lists;
+pub(crate) mod macro_names;
 
 // This macro defines configuration options used in rustfmt. Each option
 // is defined as follows:
@@ -67,6 +72,8 @@
     format_macro_matchers: bool, false, false,
         "Format the metavariable matching patterns in macros";
     format_macro_bodies: bool, true, false, "Format the bodies of macros";
+    skip_macro_invocations: MacroSelectors, MacroSelectors::default(), false,
+        "Skip formatting the bodies of macros invoked with the following names.";
     hex_literal_case: HexLiteralCase, HexLiteralCase::Preserve, false,
         "Format hexadecimal integer literals";
 
     force_multiline_blocks: bool, false, false,
         "Force multiline closure bodies and match arms to be wrapped in a block";
     fn_args_layout: Density, Density::Tall, true,
-        "Control the layout of arguments in a function";
+        "(deprecated: use fn_params_layout instead)";
+    fn_params_layout: Density, Density::Tall, true,
+        "Control the layout of parameters in function signatures.";
     brace_style: BraceStyle, BraceStyle::SameLineWhere, false, "Brace style for items";
     control_brace_style: ControlBraceStyle, ControlBraceStyle::AlwaysSameLine, false,
         "Brace style for control flow constructs";
     make_backup: bool, false, false, "Backup changed files";
     print_misformatted_file_names: bool, false, true,
         "Prints the names of mismatched files that were formatted. Prints the names of \
-         files that would be formated when used with `--check` mode. ";
+         files that would be formatted when used with `--check` mode. ";
 }
 
 #[derive(Error, Debug)]
@@ -191,6 +200,7 @@ pub fn to_toml(&self) -> Result<String, ToTomlError> {
         cloned.width_heuristics = None;
         cloned.print_misformatted_file_names = None;
         cloned.merge_imports = None;
+        cloned.fn_args_layout = None;
 
         ::toml::to_string(&cloned).map_err(ToTomlError)
     }
@@ -403,11 +413,21 @@ mod test {
     use super::*;
     use std::str;
 
+    use crate::config::macro_names::MacroName;
     use rustfmt_config_proc_macro::{nightly_only_test, stable_only_test};
 
     #[allow(dead_code)]
     mod mock {
         use super::super::*;
+        use rustfmt_config_proc_macro::config_type;
+
+        #[config_type]
+        pub(crate) enum PartiallyUnstableOption {
+            V1,
+            V2,
+            #[unstable_variant]
+            V3,
+        }
 
         create_config! {
             // Options that are used by the generated functions
@@ -427,6 +447,12 @@ mod mock {
                 "Merge imports";
             merge_imports: bool, false, false, "(deprecated: use imports_granularity instead)";
 
+            // fn_args_layout renamed to fn_params_layout
+            fn_args_layout: Density, Density::Tall, true,
+                "(deprecated: use fn_params_layout instead)";
+            fn_params_layout: Density, Density::Tall, true,
+                "Control the layout of parameters in a function signatures.";
+
             // Width Heuristics
             use_small_heuristics: Heuristics, Heuristics::Default, true,
                 "Whether to use different formatting for items and \
@@ -451,6 +477,63 @@ mod mock {
             // Options that are used by the tests
             stable_option: bool, false, true, "A stable option";
             unstable_option: bool, false, false, "An unstable option";
+            partially_unstable_option: PartiallyUnstableOption, PartiallyUnstableOption::V1, true,
+                "A partially unstable option";
+        }
+
+        #[cfg(test)]
+        mod partially_unstable_option {
+            use super::{Config, PartialConfig, PartiallyUnstableOption};
+            use rustfmt_config_proc_macro::{nightly_only_test, stable_only_test};
+            use std::path::Path;
+
+            /// From the config file, we can fill with a stable variant
+            #[test]
+            fn test_from_toml_stable_value() {
+                let toml = r#"
+                    partially_unstable_option = "V2"
+                "#;
+                let partial_config: PartialConfig = toml::from_str(toml).unwrap();
+                let config = Config::default();
+                let config = config.fill_from_parsed_config(partial_config, Path::new(""));
+                assert_eq!(
+                    config.partially_unstable_option(),
+                    PartiallyUnstableOption::V2
+                );
+            }
+
+            /// From the config file, we cannot fill with an unstable variant (stable only)
+            #[stable_only_test]
+            #[test]
+            fn test_from_toml_unstable_value_on_stable() {
+                let toml = r#"
+                    partially_unstable_option = "V3"
+                "#;
+                let partial_config: PartialConfig = toml::from_str(toml).unwrap();
+                let config = Config::default();
+                let config = config.fill_from_parsed_config(partial_config, Path::new(""));
+                assert_eq!(
+                    config.partially_unstable_option(),
+                    // default value from config, i.e. fill failed
+                    PartiallyUnstableOption::V1
+                );
+            }
+
+            /// From the config file, we can fill with an unstable variant (nightly only)
+            #[nightly_only_test]
+            #[test]
+            fn test_from_toml_unstable_value_on_nightly() {
+                let toml = r#"
+                    partially_unstable_option = "V3"
+                "#;
+                let partial_config: PartialConfig = toml::from_str(toml).unwrap();
+                let config = Config::default();
+                let config = config.fill_from_parsed_config(partial_config, Path::new(""));
+                assert_eq!(
+                    config.partially_unstable_option(),
+                    PartiallyUnstableOption::V3
+                );
+            }
         }
     }
 
@@ -489,6 +572,11 @@ fn test_was_set() {
         assert_eq!(config.was_set().verbose(), false);
     }
 
+    const PRINT_DOCS_STABLE_OPTION: &str = "stable_option <boolean> Default: false";
+    const PRINT_DOCS_UNSTABLE_OPTION: &str = "unstable_option <boolean> Default: false (unstable)";
+    const PRINT_DOCS_PARTIALLY_UNSTABLE_OPTION: &str =
+        "partially_unstable_option [V1|V2|V3 (unstable)] Default: V1";
+
     #[test]
     fn test_print_docs_exclude_unstable() {
         use self::mock::Config;
@@ -497,10 +585,9 @@ fn test_print_docs_exclude_unstable() {
         Config::print_docs(&mut output, false);
 
         let s = str::from_utf8(&output).unwrap();
-
-        assert_eq!(s.contains("stable_option"), true);
-        assert_eq!(s.contains("unstable_option"), false);
-        assert_eq!(s.contains("(unstable)"), false);
+        assert_eq!(s.contains(PRINT_DOCS_STABLE_OPTION), true);
+        assert_eq!(s.contains(PRINT_DOCS_UNSTABLE_OPTION), false);
+        assert_eq!(s.contains(PRINT_DOCS_PARTIALLY_UNSTABLE_OPTION), true);
     }
 
     #[test]
@@ -511,9 +598,9 @@ fn test_print_docs_include_unstable() {
         Config::print_docs(&mut output, true);
 
         let s = str::from_utf8(&output).unwrap();
-        assert_eq!(s.contains("stable_option"), true);
-        assert_eq!(s.contains("unstable_option"), true);
-        assert_eq!(s.contains("(unstable)"), true);
+        assert_eq!(s.contains(PRINT_DOCS_STABLE_OPTION), true);
+        assert_eq!(s.contains(PRINT_DOCS_UNSTABLE_OPTION), true);
+        assert_eq!(s.contains(PRINT_DOCS_PARTIALLY_UNSTABLE_OPTION), true);
     }
 
     #[test]
@@ -541,6 +628,7 @@ fn test_dump_default_config() {
 format_strings = false
 format_macro_matchers = false
 format_macro_bodies = true
+skip_macro_invocations = []
 hex_literal_case = "Preserve"
 empty_item_single_line = true
 struct_lit_single_line = true
@@ -567,7 +655,7 @@ fn test_dump_default_config() {
 match_arm_blocks = true
 match_arm_leading_pipes = "Never"
 force_multiline_blocks = false
-fn_args_layout = "Tall"
+fn_params_layout = "Tall"
 brace_style = "SameLineWhere"
 control_brace_style = "AlwaysSameLine"
 trailing_semicolon = true
@@ -921,4 +1009,45 @@ fn test_override_single_line_if_else_max_width_exceeds_max_width() {
             assert_eq!(config.single_line_if_else_max_width(), 100);
         }
     }
+
+    #[cfg(test)]
+    mod partially_unstable_option {
+        use super::mock::{Config, PartiallyUnstableOption};
+        use super::*;
+
+        /// From the command line, we can override with a stable variant.
+        #[test]
+        fn test_override_stable_value() {
+            let mut config = Config::default();
+            config.override_value("partially_unstable_option", "V2");
+            assert_eq!(
+                config.partially_unstable_option(),
+                PartiallyUnstableOption::V2
+            );
+        }
+
+        /// From the command line, we can override with an unstable variant.
+        #[test]
+        fn test_override_unstable_value() {
+            let mut config = Config::default();
+            config.override_value("partially_unstable_option", "V3");
+            assert_eq!(
+                config.partially_unstable_option(),
+                PartiallyUnstableOption::V3
+            );
+        }
+    }
+
+    #[test]
+    fn test_override_skip_macro_invocations() {
+        let mut config = Config::default();
+        config.override_value("skip_macro_invocations", r#"["*", "println"]"#);
+        assert_eq!(
+            config.skip_macro_invocations(),
+            MacroSelectors(vec![
+                MacroSelector::All,
+                MacroSelector::Name(MacroName::new("println".to_owned()))
+            ])
+        );
+    }
 }
index 868ff045ab78b2a5705100947217e26c693938e2..3f0f217f8907d7beba609835f913806a4a542a44 100644 (file)
@@ -29,9 +29,9 @@
 use crate::string::{rewrite_string, StringFormat};
 use crate::types::{rewrite_path, PathContext};
 use crate::utils::{
-    colon_spaces, contains_skip, count_newlines, first_line_ends_with, inner_attributes,
-    last_line_extendable, last_line_width, mk_sp, outer_attributes, semicolon_for_expr,
-    unicode_str_width, wrap_str,
+    colon_spaces, contains_skip, count_newlines, filtered_str_fits, first_line_ends_with,
+    inner_attributes, last_line_extendable, last_line_width, mk_sp, outer_attributes,
+    semicolon_for_expr, unicode_str_width, wrap_str,
 };
 use crate::vertical::rewrite_with_alignment;
 use crate::visitor::FmtVisitor;
@@ -400,7 +400,10 @@ fn needs_space_after_range(rhs: &ast::Expr) -> bool {
             }
         }
         ast::ExprKind::Underscore => Some("_".to_owned()),
-        ast::ExprKind::IncludedBytes(..) => unreachable!(),
+        ast::ExprKind::FormatArgs(..) | ast::ExprKind::IncludedBytes(..) => {
+            // These do not occur in the AST because macros aren't expanded.
+            unreachable!()
+        }
         ast::ExprKind::Err => None,
     };
 
@@ -2050,8 +2053,7 @@ fn choose_rhs<R: Rewrite>(
 
             match (orig_rhs, new_rhs) {
                 (Some(ref orig_rhs), Some(ref new_rhs))
-                    if wrap_str(new_rhs.clone(), context.config.max_width(), new_shape)
-                        .is_none() =>
+                    if !filtered_str_fits(&new_rhs, context.config.max_width(), new_shape) =>
                 {
                     Some(format!("{}{}", before_space_str, orig_rhs))
                 }
index d9dc8d004aff42d4b24eea2c400ca33c6dfecbd1..339e5cef5af911675d0346344f662862c45c642a 100644 (file)
@@ -251,8 +251,8 @@ fn flatten_use_trees(
     use_trees: Vec<UseTree>,
     import_granularity: ImportGranularity,
 ) -> Vec<UseTree> {
-    // Return non-sorted single occurance of the use-trees text string;
-    // order is by first occurance of the use-tree.
+    // Return non-sorted single occurrence of the use-trees text string;
+    // order is by first occurrence of the use-tree.
     use_trees
         .into_iter()
         .flat_map(|tree| tree.flatten(import_granularity))
index a2a73f0a5fb3a2d84862f9dbfc433ae7837c25b1..25e8a024857ce9a5c541018aacb519c32ca13f0a 100644 (file)
@@ -1084,7 +1084,11 @@ pub(crate) fn format_trait(
             let item_snippet = context.snippet(item.span);
             if let Some(lo) = item_snippet.find('/') {
                 // 1 = `{`
-                let comment_hi = body_lo - BytePos(1);
+                let comment_hi = if generics.params.len() > 0 {
+                    generics.span.lo() - BytePos(1)
+                } else {
+                    body_lo - BytePos(1)
+                };
                 let comment_lo = item.span.lo() + BytePos(lo as u32);
                 if comment_lo < comment_hi {
                     match recover_missing_comment_in_span(
@@ -1241,7 +1245,7 @@ fn format_unit_struct(
 ) -> Option<String> {
     let header_str = format_header(context, p.prefix, p.ident, p.vis, offset);
     let generics_str = if let Some(generics) = p.generics {
-        let hi = context.snippet_provider.span_before(p.span, ";");
+        let hi = context.snippet_provider.span_before_last(p.span, ";");
         format_generics(
             context,
             generics,
@@ -2602,7 +2606,7 @@ fn rewrite_params(
         &param_items,
         context
             .config
-            .fn_args_layout()
+            .fn_params_layout()
             .to_list_tactic(param_items.len()),
         Separator::Comma,
         one_line_budget,
index e87850507824f03b7907f738bd5c0f8251643795..a878e6cf9b2fc0efe824d9e98baeda3b918c7586 100644 (file)
@@ -297,9 +297,9 @@ pub(crate) fn write_list<I, T>(items: I, formatting: &ListFormatting<'_>) -> Opt
         } else {
             inner_item.as_ref()
         };
-        let mut item_last_line_width = item_last_line.len() + item_sep_len;
+        let mut item_last_line_width = unicode_str_width(item_last_line) + item_sep_len;
         if item_last_line.starts_with(&**indent_str) {
-            item_last_line_width -= indent_str.len();
+            item_last_line_width -= unicode_str_width(indent_str);
         }
 
         if !item.is_substantial() {
@@ -449,7 +449,7 @@ pub(crate) fn write_list<I, T>(items: I, formatting: &ListFormatting<'_>) -> Opt
                 } else if starts_with_newline(comment) {
                     false
                 } else {
-                    comment.trim().contains('\n') || comment.trim().len() > width
+                    comment.trim().contains('\n') || unicode_str_width(comment.trim()) > width
                 };
 
                 rewrite_comment(
@@ -465,7 +465,7 @@ pub(crate) fn write_list<I, T>(items: I, formatting: &ListFormatting<'_>) -> Opt
             if !starts_with_newline(comment) {
                 if formatting.align_comments {
                     let mut comment_alignment =
-                        post_comment_alignment(item_max_width, inner_item.len());
+                        post_comment_alignment(item_max_width, unicode_str_width(inner_item));
                     if first_line_width(&formatted_comment)
                         + last_line_width(&result)
                         + comment_alignment
@@ -475,7 +475,7 @@ pub(crate) fn write_list<I, T>(items: I, formatting: &ListFormatting<'_>) -> Opt
                         item_max_width = None;
                         formatted_comment = rewrite_post_comment(&mut item_max_width)?;
                         comment_alignment =
-                            post_comment_alignment(item_max_width, inner_item.len());
+                            post_comment_alignment(item_max_width, unicode_str_width(inner_item));
                     }
                     for _ in 0..=comment_alignment {
                         result.push(' ');
@@ -533,7 +533,7 @@ fn max_width_of_item_with_post_comment<I, T>(
     let mut first = true;
     for item in items.clone().into_iter().skip(i) {
         let item = item.as_ref();
-        let inner_item_width = item.inner_as_ref().len();
+        let inner_item_width = unicode_str_width(item.inner_as_ref());
         if !first
             && (item.is_different_group()
                 || item.post_comment.is_none()
@@ -552,8 +552,8 @@ fn max_width_of_item_with_post_comment<I, T>(
     max_width
 }
 
-fn post_comment_alignment(item_max_width: Option<usize>, inner_item_len: usize) -> usize {
-    item_max_width.unwrap_or(0).saturating_sub(inner_item_len)
+fn post_comment_alignment(item_max_width: Option<usize>, inner_item_width: usize) -> usize {
+    item_max_width.unwrap_or(0).saturating_sub(inner_item_width)
 }
 
 pub(crate) struct ListItems<'a, I, F1, F2, F3>
index df949388037880dfbf3dbde847b83807561b1269..d58f7547fefb3364f9cae0c308c6bff8d2ca94cf 100644 (file)
@@ -35,8 +35,8 @@
 use crate::source_map::SpanUtils;
 use crate::spanned::Spanned;
 use crate::utils::{
-    format_visibility, indent_next_line, is_empty_line, mk_sp, remove_trailing_white_spaces,
-    rewrite_ident, trim_left_preserve_layout, wrap_str, NodeIdExt,
+    filtered_str_fits, format_visibility, indent_next_line, is_empty_line, mk_sp,
+    remove_trailing_white_spaces, rewrite_ident, trim_left_preserve_layout, NodeIdExt,
 };
 use crate::visitor::FmtVisitor;
 
@@ -157,7 +157,8 @@ pub(crate) fn rewrite_macro(
 ) -> Option<String> {
     let should_skip = context
         .skip_context
-        .skip_macro(context.snippet(mac.path.span));
+        .macros
+        .skip(context.snippet(mac.path.span));
     if should_skip {
         None
     } else {
@@ -1265,15 +1266,14 @@ fn rewrite(
                 }
             }
         };
-        let new_body = wrap_str(
-            new_body_snippet.snippet.to_string(),
-            config.max_width(),
-            shape,
-        )?;
+
+        if !filtered_str_fits(&new_body_snippet.snippet, config.max_width(), shape) {
+            return None;
+        }
 
         // Indent the body since it is in a block.
         let indent_str = body_indent.to_string(&config);
-        let mut new_body = LineClasses::new(new_body.trim_end())
+        let mut new_body = LineClasses::new(new_body_snippet.snippet.trim_end())
             .enumerate()
             .fold(
                 (String::new(), true),
index 032922d421df7a340d9f55b699bb7ffac46a0a6d..68f85b2ade48a6191bd1110aa6dce2964ed39b41 100644 (file)
@@ -2,33 +2,84 @@
 
 use rustc_ast::ast;
 use rustc_ast_pretty::pprust;
+use std::collections::HashSet;
 
-/// Take care of skip name stack. You can update it by attributes slice or
-/// by other context. Query this context to know if you need skip a block.
+/// Track which blocks of code are to be skipped when formatting.
+///
+/// You can update it by:
+///
+/// - attributes slice
+/// - manually feeding values into the underlying contexts
+///
+/// Query this context to know if you need to skip a block.
 #[derive(Default, Clone)]
 pub(crate) struct SkipContext {
-    macros: Vec<String>,
-    attributes: Vec<String>,
+    pub(crate) macros: SkipNameContext,
+    pub(crate) attributes: SkipNameContext,
 }
 
 impl SkipContext {
     pub(crate) fn update_with_attrs(&mut self, attrs: &[ast::Attribute]) {
-        self.macros.append(&mut get_skip_names("macros", attrs));
-        self.attributes
-            .append(&mut get_skip_names("attributes", attrs));
+        self.macros.extend(get_skip_names("macros", attrs));
+        self.attributes.extend(get_skip_names("attributes", attrs));
     }
 
-    pub(crate) fn update(&mut self, mut other: SkipContext) {
-        self.macros.append(&mut other.macros);
-        self.attributes.append(&mut other.attributes);
+    pub(crate) fn update(&mut self, other: SkipContext) {
+        let SkipContext { macros, attributes } = other;
+        self.macros.update(macros);
+        self.attributes.update(attributes);
+    }
+}
+
+/// Track which names to skip.
+///
+/// Query this context with a string to know whether to skip it.
+#[derive(Clone)]
+pub(crate) enum SkipNameContext {
+    All,
+    Values(HashSet<String>),
+}
+
+impl Default for SkipNameContext {
+    fn default() -> Self {
+        Self::Values(Default::default())
+    }
+}
+
+impl Extend<String> for SkipNameContext {
+    fn extend<T: IntoIterator<Item = String>>(&mut self, iter: T) {
+        match self {
+            Self::All => {}
+            Self::Values(values) => values.extend(iter),
+        }
+    }
+}
+
+impl SkipNameContext {
+    pub(crate) fn update(&mut self, other: Self) {
+        match (self, other) {
+            // If we're already skipping everything, nothing more can be added
+            (Self::All, _) => {}
+            // If we want to skip all, set it
+            (this, Self::All) => {
+                *this = Self::All;
+            }
+            // If we have some new values to skip, add them
+            (Self::Values(existing_values), Self::Values(new_values)) => {
+                existing_values.extend(new_values)
+            }
+        }
     }
 
-    pub(crate) fn skip_macro(&self, name: &str) -> bool {
-        self.macros.iter().any(|n| n == name)
+    pub(crate) fn skip(&self, name: &str) -> bool {
+        match self {
+            Self::All => true,
+            Self::Values(values) => values.contains(name),
+        }
     }
 
-    pub(crate) fn skip_attribute(&self, name: &str) -> bool {
-        self.attributes.iter().any(|n| n == name)
+    pub(crate) fn skip_all(&mut self) {
+        *self = Self::All;
     }
 }
 
index c8fda7c8556db9ea4f42704db5ad34dbb24d48d1..c70b3c5facd50e68635d682c16471acd50900c3a 100644 (file)
@@ -27,8 +27,13 @@ fn get_section<I: Iterator<Item = String>>(
         lazy_static! {
             static ref CONFIG_NAME_REGEX: regex::Regex =
                 regex::Regex::new(r"^## `([^`]+)`").expect("failed creating configuration pattern");
+            // Configuration values, which will be passed to `from_str`:
+            //
+            // - must be prefixed with `####`
+            // - must be wrapped in backticks
+            // - may by wrapped in double quotes (which will be stripped)
             static ref CONFIG_VALUE_REGEX: regex::Regex =
-                regex::Regex::new(r#"^#### `"?([^`"]+)"?`"#)
+                regex::Regex::new(r#"^#### `"?([^`]+?)"?`"#)
                     .expect("failed creating configuration value pattern");
         }
 
index 6b5bc2b30dd5ad5895cdbec355ad7421212a0959..cfad4a8ed0e3eeaff398bced4928fc170ca1744e 100644 (file)
@@ -982,11 +982,7 @@ fn rustfmt() -> PathBuf {
     assert!(
         me.is_file() || me.with_extension("exe").is_file(),
         "{}",
-        if cfg!(release) {
-            "no rustfmt bin, try running `cargo build --release` before testing"
-        } else {
-            "no rustfmt bin, try running `cargo build` before testing"
-        }
+        "no rustfmt bin, try running `cargo build` or `cargo build --release` before testing"
     );
     me
 }
index c1991e8d2c80800ef354d7ccc5554928349450be..01e2fb6e61e159368f65b5dd9a5df9edec4091c3 100644 (file)
@@ -941,6 +941,28 @@ fn join_bounds_inner(
         ast::GenericBound::Trait(..) => last_line_extendable(s),
     };
 
+    // Whether a GenericBound item is a PathSegment segment that includes internal array
+    // that contains more than one item
+    let is_item_with_multi_items_array = |item: &ast::GenericBound| match item {
+        ast::GenericBound::Trait(ref poly_trait_ref, ..) => {
+            let segments = &poly_trait_ref.trait_ref.path.segments;
+            if segments.len() > 1 {
+                true
+            } else {
+                if let Some(args_in) = &segments[0].args {
+                    matches!(
+                        args_in.deref(),
+                        ast::GenericArgs::AngleBracketed(bracket_args)
+                            if bracket_args.args.len() > 1
+                    )
+                } else {
+                    false
+                }
+            }
+        }
+        _ => false,
+    };
+
     let result = items.iter().enumerate().try_fold(
         (String::new(), None, false),
         |(strs, prev_trailing_span, prev_extendable), (i, item)| {
@@ -1035,10 +1057,24 @@ fn join_bounds_inner(
         },
     )?;
 
-    if !force_newline
-        && items.len() > 1
-        && (result.0.contains('\n') || result.0.len() > shape.width)
-    {
+    // Whether to retry with a forced newline:
+    //   Only if result is not already multiline and did not exceed line width,
+    //   and either there is more than one item;
+    //       or the single item is of type `Trait`,
+    //          and any of the internal arrays contains more than one item;
+    let retry_with_force_newline = match context.config.version() {
+        Version::One => {
+            !force_newline
+                && items.len() > 1
+                && (result.0.contains('\n') || result.0.len() > shape.width)
+        }
+        Version::Two if force_newline => false,
+        Version::Two if (!result.0.contains('\n') && result.0.len() <= shape.width) => false,
+        Version::Two if items.len() > 1 => true,
+        Version::Two => is_item_with_multi_items_array(&items[0]),
+    };
+
+    if retry_with_force_newline {
         join_bounds_inner(context, shape, items, need_indent, true)
     } else {
         Some(result.0)
index 3e884419f1a32c84406947b74ae678979577bfef..1e89f3ae75f8167b7ebfb170a0731411a65220b7 100644 (file)
@@ -384,14 +384,15 @@ macro_rules! skip_out_of_file_lines_range_visitor {
 // Wraps String in an Option. Returns Some when the string adheres to the
 // Rewrite constraints defined for the Rewrite trait and None otherwise.
 pub(crate) fn wrap_str(s: String, max_width: usize, shape: Shape) -> Option<String> {
-    if is_valid_str(&filter_normal_code(&s), max_width, shape) {
+    if filtered_str_fits(&s, max_width, shape) {
         Some(s)
     } else {
         None
     }
 }
 
-fn is_valid_str(snippet: &str, max_width: usize, shape: Shape) -> bool {
+pub(crate) fn filtered_str_fits(snippet: &str, max_width: usize, shape: Shape) -> bool {
+    let snippet = &filter_normal_code(snippet);
     if !snippet.is_empty() {
         // First line must fits with `shape.width`.
         if first_line_width(snippet) > shape.width {
@@ -462,6 +463,7 @@ pub(crate) fn first_line_ends_with(s: &str, c: char) -> bool {
 pub(crate) fn is_block_expr(context: &RewriteContext<'_>, expr: &ast::Expr, repr: &str) -> bool {
     match expr.kind {
         ast::ExprKind::MacCall(..)
+        | ast::ExprKind::FormatArgs(..)
         | ast::ExprKind::Call(..)
         | ast::ExprKind::MethodCall(..)
         | ast::ExprKind::Array(..)
index 9c3cc7820d2991b64e807e1edf4129e3138e6c7e..f4d84d1381fc0c3745ec463ae839204a3bf8f644 100644 (file)
@@ -8,7 +8,7 @@
 use crate::attr::*;
 use crate::comment::{contains_comment, rewrite_comment, CodeCharKind, CommentCodeSlices};
 use crate::config::Version;
-use crate::config::{BraceStyle, Config};
+use crate::config::{BraceStyle, Config, MacroSelector};
 use crate::coverage::transform_missing_snippet;
 use crate::items::{
     format_impl, format_trait, format_trait_alias, is_mod_decl, is_use_item, rewrite_extern_crate,
@@ -770,6 +770,15 @@ pub(crate) fn from_parse_sess(
         snippet_provider: &'a SnippetProvider,
         report: FormatReport,
     ) -> FmtVisitor<'a> {
+        let mut skip_context = SkipContext::default();
+        let mut macro_names = Vec::new();
+        for macro_selector in config.skip_macro_invocations().0 {
+            match macro_selector {
+                MacroSelector::Name(name) => macro_names.push(name.to_string()),
+                MacroSelector::All => skip_context.macros.skip_all(),
+            }
+        }
+        skip_context.macros.extend(macro_names);
         FmtVisitor {
             parent_context: None,
             parse_sess: parse_session,
@@ -784,7 +793,7 @@ pub(crate) fn from_parse_sess(
             is_macro_def: false,
             macro_rewrite_failure: false,
             report,
-            skip_context: Default::default(),
+            skip_context,
         }
     }
 
index 348876cd264fa3a0e0df022a4eb0c7c09cb71fda..701c36fadeafa835f8e5c4372e65c34c01512bba 100644 (file)
@@ -4,6 +4,8 @@
 use std::path::Path;
 use std::process::Command;
 
+use rustfmt_config_proc_macro::rustfmt_only_ci_test;
+
 /// Run the cargo-fmt executable and return its output.
 fn cargo_fmt(args: &[&str]) -> (String, String) {
     let mut bin_dir = env::current_exe().unwrap();
@@ -47,7 +49,7 @@ macro_rules! assert_that {
     };
 }
 
-#[ignore]
+#[rustfmt_only_ci_test]
 #[test]
 fn version() {
     assert_that!(&["--version"], starts_with("rustfmt "));
@@ -56,7 +58,7 @@ fn version() {
     assert_that!(&["--", "--version"], starts_with("rustfmt "));
 }
 
-#[ignore]
+#[rustfmt_only_ci_test]
 #[test]
 fn print_config() {
     assert_that!(
@@ -65,7 +67,7 @@ fn print_config() {
     );
 }
 
-#[ignore]
+#[rustfmt_only_ci_test]
 #[test]
 fn rustfmt_help() {
     assert_that!(&["--", "--help"], contains("Format Rust code"));
@@ -73,7 +75,7 @@ fn rustfmt_help() {
     assert_that!(&["--", "--help=config"], contains("Configuration Options:"));
 }
 
-#[ignore]
+#[rustfmt_only_ci_test]
 #[test]
 fn cargo_fmt_out_of_line_test_modules() {
     // See also https://github.com/rust-lang/rustfmt/issues/5119
@@ -96,3 +98,22 @@ fn cargo_fmt_out_of_line_test_modules() {
         assert!(stdout.contains(&format!("Diff in {}", path.display())))
     }
 }
+
+#[rustfmt_only_ci_test]
+#[test]
+fn cargo_fmt_emits_error_on_line_overflow_true() {
+    // See also https://github.com/rust-lang/rustfmt/issues/3164
+    let args = [
+        "--check",
+        "--manifest-path",
+        "tests/cargo-fmt/source/issue_3164/Cargo.toml",
+        "--",
+        "--config",
+        "error_on_line_overflow=true",
+    ];
+
+    let (_stdout, stderr) = cargo_fmt(&args);
+    assert!(stderr.contains(
+        "line formatted, but exceeded maximum width (maximum: 100 (see `max_width` option)"
+    ))
+}
diff --git a/src/tools/rustfmt/tests/cargo-fmt/source/issue_3164/Cargo.toml b/src/tools/rustfmt/tests/cargo-fmt/source/issue_3164/Cargo.toml
new file mode 100644 (file)
index 0000000..580ef7e
--- /dev/null
@@ -0,0 +1,8 @@
+[package]
+name = "issue_3164"
+version = "0.1.0"
+edition = "2021"
+
+# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+
+[dependencies]
diff --git a/src/tools/rustfmt/tests/cargo-fmt/source/issue_3164/src/main.rs b/src/tools/rustfmt/tests/cargo-fmt/source/issue_3164/src/main.rs
new file mode 100644 (file)
index 0000000..9330107
--- /dev/null
@@ -0,0 +1,13 @@
+#[allow(unused_macros)]
+macro_rules! foo {
+    ($id:ident) => {
+        macro_rules! bar {
+            ($id2:tt) => {
+                #[cfg(any(target_feature = $id2, target_feature = $id2, target_feature = $id2, target_feature = $id2, target_feature = $id2))]
+                fn $id() {}
+            };
+        }
+    };
+}
+
+fn main() {}
index c3cfd34317a377132f034e8a22c028bfac0a932d..4c37100894f832b92553e00a21286511ba0c9135 100644 (file)
@@ -3,7 +3,7 @@ comment_width = 80
 tab_spaces = 2
 newline_style = "Unix"
 brace_style = "SameLineWhere"
-fn_args_layout = "Tall"
+fn_params_layout = "Tall"
 trailing_comma = "Vertical"
 indent_style = "Block"
 reorder_imports = false
index 92c9e3021431f84d78a57e0f2838c145f173a78d..254102ebabdc25cdceca176107ed3cbc2ae1b4bb 100644 (file)
@@ -9,7 +9,7 @@ The directory name './lib/c/d/' conflicts with the './lib/c/d.rs' file name.
     * mod g;
 
 Module resolution will fail if we look for './lib/c/d/e.rs' or './lib/c/d/e/mod.rs',
-so we should fall back to looking for './lib/c/e.rs', which correctly finds the modlue, that
+so we should fall back to looking for './lib/c/e.rs', which correctly finds the module, that
 rustfmt should format.
 
 './lib/c/d/f.rs' and './lib/c/d/g/mod.rs' exist at the default submodule paths so we should be able
index d436a8076cd717accfd288772ca1c2d4e46c41fe..90464def8ebcc29a5a4be21bc44f4bc3e43245b8 100644 (file)
@@ -9,7 +9,7 @@ The directory name './lib' conflicts with the './lib.rs' file name.
     * mod c;
 
 Module resolution will fail if we look for './lib/a.rs' or './lib/a/mod.rs',
-so we should fall back to looking for './a.rs', which correctly finds the modlue that
+so we should fall back to looking for './a.rs', which correctly finds the module that
 rustfmt should format.
 
 './lib/b.rs' and './lib/c/mod.rs' exist at the default submodule paths so we should be able
index 4c6d52726f3fe0525d391642570583e6997cec44..7ff301e80195aa0efdebdaf740e98697a8eaafb8 100644 (file)
@@ -5,6 +5,8 @@
 use std::path::Path;
 use std::process::Command;
 
+use rustfmt_config_proc_macro::rustfmt_only_ci_test;
+
 /// Run the rustfmt executable and return its output.
 fn rustfmt(args: &[&str]) -> (String, String) {
     let mut bin_dir = env::current_exe().unwrap();
@@ -47,7 +49,7 @@ macro_rules! assert_that {
     };
 }
 
-#[ignore]
+#[rustfmt_only_ci_test]
 #[test]
 fn print_config() {
     assert_that!(
@@ -76,7 +78,7 @@ fn print_config() {
     remove_file("minimal-config").unwrap();
 }
 
-#[ignore]
+#[rustfmt_only_ci_test]
 #[test]
 fn inline_config() {
     // single invocation
@@ -157,3 +159,18 @@ fn mod_resolution_error_path_attribute_does_not_exist() {
     // The path attribute points to a file that does not exist
     assert!(stderr.contains("does_not_exist.rs does not exist"));
 }
+
+#[test]
+fn rustfmt_emits_error_on_line_overflow_true() {
+    // See also https://github.com/rust-lang/rustfmt/issues/3164
+    let args = [
+        "--config",
+        "error_on_line_overflow=true",
+        "tests/cargo-fmt/source/issue_3164/src/main.rs",
+    ];
+
+    let (_stdout, stderr) = rustfmt(&args);
+    assert!(stderr.contains(
+        "line formatted, but exceeded maximum width (maximum: 100 (see `max_width` option)"
+    ))
+}
index d26f4ee894fad47e06775b84580d806c16109734..131cbb855f163115b08a73dacb41fb7a05f2675c 100644 (file)
@@ -329,7 +329,7 @@ pub enum Feature {
     tbm,
     /// POPCNT (Population Count)
     popcnt,
-    /// FXSR (Floating-point context fast save and restor)
+    /// FXSR (Floating-point context fast save and restore)
     fxsr,
     /// XSAVE (Save Processor Extended States)
     xsave,
diff --git a/src/tools/rustfmt/tests/source/comments_unicode.rs b/src/tools/rustfmt/tests/source/comments_unicode.rs
new file mode 100644 (file)
index 0000000..e65a245
--- /dev/null
@@ -0,0 +1,140 @@
+impl Default for WhitespaceCharacters {
+    fn default() -> Self {
+        Self {
+            space: '·',    // U+00B7
+            nbsp: '⍽',    // U+237D
+            tab: '→',     // U+2192
+            newline: '⏎', // U+23CE
+        }
+    }
+}
+
+const RAINBOWS: &[&str] = &[
+    "rаinЬοѡ",    // hue: 0
+    "raіnЬοw",     // hue: 2
+    "rаіɴЬow",    // hue: 2
+    "raіɴЬoѡ",    // hue: 8
+    "ʀainЬow",      // hue: 8
+    "ʀaіɴboѡ",    // hue: 8
+    "ʀаіnbοw",    // hue: 11
+    "rainЬoѡ",      // hue: 14
+    "raіɴbow",      // hue: 14
+    "rаiɴЬow",     // hue: 20
+    "raіnЬow",      // hue: 26
+    "ʀaiɴbοw",     // hue: 32
+    "raіɴboѡ",     // hue: 35
+    "rаiɴbow",      // hue: 35
+    "rаіnbοw",     // hue: 38
+    "rаinЬow",      // hue: 47
+    "ʀaіnboѡ",     // hue: 47
+    "ʀaіnЬoѡ",    // hue: 47
+    "ʀаіɴbοw",   // hue: 53
+    "ʀaіnЬοѡ",   // hue: 57
+    "raiɴЬoѡ",     // hue: 68
+    "ʀainbοѡ",     // hue: 68
+    "ʀаinboѡ",     // hue: 68
+    "ʀаiɴbοw",    // hue: 68
+    "ʀаіnbow",     // hue: 68
+    "rаіnЬοѡ",   // hue: 69
+    "ʀainЬοw",     // hue: 71
+    "raiɴbow",       // hue: 73
+    "raіnЬoѡ",     // hue: 74
+    "rаіɴbοw",    // hue: 77
+    "raіnЬοѡ",    // hue: 81
+    "raiɴЬow",      // hue: 83
+    "ʀainbοw",      // hue: 83
+    "ʀаinbow",      // hue: 83
+    "ʀаiɴbοѡ",   // hue: 83
+    "ʀаіnboѡ",    // hue: 83
+    "ʀаіɴЬοѡ", // hue: 84
+    "rainЬow",       // hue: 85
+    "ʀаiɴЬοw",   // hue: 86
+    "ʀаіnbοѡ",   // hue: 89
+    "ʀаіnЬοw",   // hue: 92
+    "rаiɴbοw",     // hue: 95
+    "ʀаіɴbοѡ",  // hue: 98
+    "ʀаiɴЬοѡ",  // hue: 99
+    "raіnbοw",      // hue: 101
+    "ʀаіɴЬοw",  // hue: 101
+    "ʀaiɴboѡ",     // hue: 104
+    "ʀаinbοѡ",    // hue: 104
+    "rаiɴbοѡ",    // hue: 107
+    "ʀаinЬοw",    // hue: 107
+    "rаiɴЬοw",    // hue: 110
+    "rаіnboѡ",     // hue: 110
+    "rаіnbοѡ",    // hue: 113
+    "ʀainЬοѡ",    // hue: 114
+    "rаіnЬοw",    // hue: 116
+    "ʀaіɴЬow",    // hue: 116
+    "rаinbοw",      // hue: 122
+    "ʀаіɴboѡ",   // hue: 125
+    "rаinbοѡ",     // hue: 131
+    "rainbow",        // hue: 134
+    "rаinЬοw",     // hue: 134
+    "ʀаiɴboѡ",    // hue: 140
+    "rainЬοѡ",     // hue: 141
+    "raіɴЬow",     // hue: 143
+    "ʀainЬoѡ",     // hue: 143
+    "ʀaіɴbow",     // hue: 143
+    "ʀainbow",       // hue: 148
+    "rаіɴboѡ",    // hue: 149
+    "ʀainboѡ",      // hue: 155
+    "ʀaіnbow",      // hue: 155
+    "ʀaіnЬow",     // hue: 155
+    "raiɴbοw",      // hue: 158
+    "ʀаiɴЬoѡ",   // hue: 158
+    "rainbοw",       // hue: 160
+    "rаinbow",       // hue: 160
+    "ʀaіɴbοѡ",   // hue: 164
+    "ʀаiɴbow",     // hue: 164
+    "ʀаіnЬoѡ",   // hue: 164
+    "ʀaiɴЬοѡ",   // hue: 165
+    "rаiɴboѡ",     // hue: 167
+    "ʀaіɴЬοw",   // hue: 167
+    "ʀaіɴЬοѡ",  // hue: 171
+    "raіnboѡ",      // hue: 173
+    "ʀаіɴЬoѡ",  // hue: 173
+    "rаіɴbοѡ",   // hue: 176
+    "ʀаinЬow",     // hue: 176
+    "rаiɴЬοѡ",   // hue: 177
+    "rаіɴЬοw",   // hue: 179
+    "ʀаinЬoѡ",    // hue: 179
+    "ʀаіɴbow",    // hue: 179
+    "rаiɴЬoѡ",    // hue: 182
+    "raіɴbοѡ",    // hue: 188
+    "rаіnЬoѡ",    // hue: 188
+    "raiɴЬοѡ",    // hue: 189
+    "raіɴЬοw",    // hue: 191
+    "ʀaіɴbοw",    // hue: 191
+    "ʀаіnЬow",    // hue: 191
+    "rainbοѡ",      // hue: 194
+    "rаinboѡ",      // hue: 194
+    "rаіnbow",      // hue: 194
+    "rainЬοw",      // hue: 197
+    "rаinЬoѡ",     // hue: 206
+    "rаіɴbow",     // hue: 206
+    "rаіɴЬοѡ",  // hue: 210
+    "ʀaiɴЬow",     // hue: 212
+    "raіɴbοw",     // hue: 218
+    "rаіnЬow",     // hue: 218
+    "ʀaiɴbοѡ",    // hue: 221
+    "ʀaiɴЬοw",    // hue: 224
+    "ʀaіnbοѡ",    // hue: 227
+    "raiɴboѡ",      // hue: 230
+    "ʀaіnbοw",     // hue: 230
+    "ʀaіnЬοw",    // hue: 230
+    "ʀаinЬοѡ",   // hue: 231
+    "rainboѡ",       // hue: 232
+    "raіnbow",       // hue: 232
+    "ʀаіɴЬow",   // hue: 233
+    "ʀaіɴЬoѡ",   // hue: 239
+    "ʀаіnЬοѡ",  // hue: 246
+    "raiɴbοѡ",     // hue: 248
+    "ʀаiɴЬow",    // hue: 248
+    "raіɴЬοѡ",   // hue: 249
+    "raiɴЬοw",     // hue: 251
+    "rаіɴЬoѡ",   // hue: 251
+    "ʀaiɴbow",      // hue: 251
+    "ʀаinbοw",     // hue: 251
+    "raіnbοѡ",     // hue: 254
+];
diff --git a/src/tools/rustfmt/tests/source/configs/fn_args_layout/compressed.rs b/src/tools/rustfmt/tests/source/configs/fn_args_layout/compressed.rs
deleted file mode 100644 (file)
index 66a371c..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-// rustfmt-fn_args_layout: Compressed
-// Function arguments density
-
-trait Lorem {
-    fn lorem(ipsum: Ipsum, dolor: Dolor, sit: Sit, amet: Amet);
-
-    fn lorem(ipsum: Ipsum, dolor: Dolor, sit: Sit, amet: Amet) {
-        // body
-    }
-
-    fn lorem(ipsum: Ipsum, dolor: Dolor, sit: Sit, amet: Amet, consectetur: onsectetur, adipiscing: Adipiscing, elit: Elit);
-
-    fn lorem(ipsum: Ipsum, dolor: Dolor, sit: Sit, amet: Amet, consectetur: onsectetur, adipiscing: Adipiscing, elit: Elit) {
-        // body
-    }
-}
diff --git a/src/tools/rustfmt/tests/source/configs/fn_args_layout/tall.rs b/src/tools/rustfmt/tests/source/configs/fn_args_layout/tall.rs
deleted file mode 100644 (file)
index f11e86f..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-// rustfmt-fn_args_layout: Tall
-// Function arguments density
-
-trait Lorem {
-    fn lorem(ipsum: Ipsum, dolor: Dolor, sit: Sit, amet: Amet);
-
-    fn lorem(ipsum: Ipsum, dolor: Dolor, sit: Sit, amet: Amet) {
-        // body
-    }
-
-    fn lorem(ipsum: Ipsum, dolor: Dolor, sit: Sit, amet: Amet, consectetur: onsectetur, adipiscing: Adipiscing, elit: Elit);
-
-    fn lorem(ipsum: Ipsum, dolor: Dolor, sit: Sit, amet: Amet, consectetur: onsectetur, adipiscing: Adipiscing, elit: Elit) {
-        // body
-    }
-}
diff --git a/src/tools/rustfmt/tests/source/configs/fn_args_layout/vertical.rs b/src/tools/rustfmt/tests/source/configs/fn_args_layout/vertical.rs
deleted file mode 100644 (file)
index a23cc02..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-// rustfmt-fn_args_layout: Vertical
-// Function arguments density
-
-trait Lorem {
-    fn lorem(ipsum: Ipsum, dolor: Dolor, sit: Sit, amet: Amet);
-
-    fn lorem(ipsum: Ipsum, dolor: Dolor, sit: Sit, amet: Amet) {
-        // body
-    }
-
-    fn lorem(ipsum: Ipsum, dolor: Dolor, sit: Sit, amet: Amet, consectetur: onsectetur, adipiscing: Adipiscing, elit: Elit);
-
-    fn lorem(ipsum: Ipsum, dolor: Dolor, sit: Sit, amet: Amet, consectetur: onsectetur, adipiscing: Adipiscing, elit: Elit) {
-        // body
-    }
-}
diff --git a/src/tools/rustfmt/tests/source/configs/fn_params_layout/compressed.rs b/src/tools/rustfmt/tests/source/configs/fn_params_layout/compressed.rs
new file mode 100644 (file)
index 0000000..eb573d3
--- /dev/null
@@ -0,0 +1,16 @@
+// rustfmt-fn_params_layout: Compressed
+// Function arguments density
+
+trait Lorem {
+    fn lorem(ipsum: Ipsum, dolor: Dolor, sit: Sit, amet: Amet);
+
+    fn lorem(ipsum: Ipsum, dolor: Dolor, sit: Sit, amet: Amet) {
+        // body
+    }
+
+    fn lorem(ipsum: Ipsum, dolor: Dolor, sit: Sit, amet: Amet, consectetur: onsectetur, adipiscing: Adipiscing, elit: Elit);
+
+    fn lorem(ipsum: Ipsum, dolor: Dolor, sit: Sit, amet: Amet, consectetur: onsectetur, adipiscing: Adipiscing, elit: Elit) {
+        // body
+    }
+}
diff --git a/src/tools/rustfmt/tests/source/configs/fn_params_layout/tall.rs b/src/tools/rustfmt/tests/source/configs/fn_params_layout/tall.rs
new file mode 100644 (file)
index 0000000..4be34f0
--- /dev/null
@@ -0,0 +1,16 @@
+// rustfmt-fn_params_layout: Tall
+// Function arguments density
+
+trait Lorem {
+    fn lorem(ipsum: Ipsum, dolor: Dolor, sit: Sit, amet: Amet);
+
+    fn lorem(ipsum: Ipsum, dolor: Dolor, sit: Sit, amet: Amet) {
+        // body
+    }
+
+    fn lorem(ipsum: Ipsum, dolor: Dolor, sit: Sit, amet: Amet, consectetur: onsectetur, adipiscing: Adipiscing, elit: Elit);
+
+    fn lorem(ipsum: Ipsum, dolor: Dolor, sit: Sit, amet: Amet, consectetur: onsectetur, adipiscing: Adipiscing, elit: Elit) {
+        // body
+    }
+}
diff --git a/src/tools/rustfmt/tests/source/configs/fn_params_layout/vertical.rs b/src/tools/rustfmt/tests/source/configs/fn_params_layout/vertical.rs
new file mode 100644 (file)
index 0000000..6749680
--- /dev/null
@@ -0,0 +1,16 @@
+// rustfmt-fn_params_layout: Vertical
+// Function arguments density
+
+trait Lorem {
+    fn lorem(ipsum: Ipsum, dolor: Dolor, sit: Sit, amet: Amet);
+
+    fn lorem(ipsum: Ipsum, dolor: Dolor, sit: Sit, amet: Amet) {
+        // body
+    }
+
+    fn lorem(ipsum: Ipsum, dolor: Dolor, sit: Sit, amet: Amet, consectetur: onsectetur, adipiscing: Adipiscing, elit: Elit);
+
+    fn lorem(ipsum: Ipsum, dolor: Dolor, sit: Sit, amet: Amet, consectetur: onsectetur, adipiscing: Adipiscing, elit: Elit) {
+        // body
+    }
+}
index 0ed9651abe7221846d9d141d8f0e3a2d0429cc65..a7b9616929cb00137c0ae462ef9cc26916aa1d55 100644 (file)
@@ -36,7 +36,7 @@ enum StructLikeVariants {
     Normal(u32, String, ),
     StructLike { x: i32, // Test comment
         // Pre-comment
-        #[Attr50] y: SomeType, // Aanother Comment
+        #[Attr50] y: SomeType, // Another Comment
     }, SL { a: A }
 }
 
index d5330196bf79536431a3584bc4832fae6e828369..3ecd8701727ad0a3ae46954b83bd5b7e4901fd7e 100644 (file)
@@ -1,5 +1,5 @@
 // rustfmt-normalize_comments: true
-// rustfmt-fn_args_layout: Vertical
+// rustfmt-fn_params_layout: Vertical
 // rustfmt-brace_style: AlwaysNextLine
 
 // Case with only one variable.
index 77ced4c5e0e101cbf7f11f799efdc736ccae183d..64ef0ecfaae49f4d1219d98856d9df5d7d3147d7 100644 (file)
@@ -1,4 +1,4 @@
-// rustfmt-fn_args_layout: Compressed
+// rustfmt-fn_params_layout: Compressed
 // Test some of the ways function signatures can be customised.
 
 // Test compressed layout of args.
index 759bc83d015708f2e6801811bdacc835d6a60abf..fd6e3f0442ec14fc3ae2f65080cbd28476c194b9 100644 (file)
@@ -1,4 +1,4 @@
-// rustfmt-fn_args_layout: Vertical
+// rustfmt-fn_params_layout: Vertical
 
 // Empty list should stay on one line.
 fn do_bar(
diff --git a/src/tools/rustfmt/tests/source/issue-3987/format_macro_bodies_true.rs b/src/tools/rustfmt/tests/source/issue-3987/format_macro_bodies_true.rs
new file mode 100644 (file)
index 0000000..9af114f
--- /dev/null
@@ -0,0 +1,26 @@
+// rustfmt-format_macro_bodies: true
+
+// with comments
+macro_rules! macros {
+    () => {{
+        Struct {
+            field: (
+                42 + //comment 1
+                42
+                //comment 2
+            ),
+        };
+    }};
+}
+
+// without comments
+macro_rules! macros {
+    () => {{
+        Struct {
+            field: (
+                42 +
+                42
+            ),
+        };
+    }};
+}
diff --git a/src/tools/rustfmt/tests/source/issue-4643.rs b/src/tools/rustfmt/tests/source/issue-4643.rs
new file mode 100644 (file)
index 0000000..382072d
--- /dev/null
@@ -0,0 +1,23 @@
+// output doesn't get corrupted when using comments within generic type parameters of a trait
+
+pub trait Something<
+    A,
+    // some comment
+    B,
+    C
+> {
+    fn a(&self, x: A) -> i32;
+    fn b(&self, x: B) -> i32;
+    fn c(&self, x: C) -> i32;
+}
+
+pub trait SomethingElse<
+    A,
+    /* some comment */
+    B,
+    C
+> {
+    fn a(&self, x: A) -> i32;
+    fn b(&self, x: B) -> i32;
+    fn c(&self, x: C) -> i32;
+}
diff --git a/src/tools/rustfmt/tests/source/issue-4689/one.rs b/src/tools/rustfmt/tests/source/issue-4689/one.rs
new file mode 100644 (file)
index 0000000..d048eb1
--- /dev/null
@@ -0,0 +1,149 @@
+// rustfmt-version: One
+
+// Based on the issue description
+pub trait PrettyPrinter<'tcx>:
+Printer<
+'tcx,
+Error = fmt::Error,
+Path = Self,
+Region = Self,
+Type = Self,
+DynExistential = Self,
+Const = Self,
+>
+{
+//
+}
+pub trait PrettyPrinter<'tcx>:
+Printer<
+'tcx,
+Error = fmt::Error,
+Path = Self,
+Region = Self,
+Type = Self,
+DynExistential = Self,
+Const = Self,
+> + fmt::Write
+{
+//
+}
+pub trait PrettyPrinter<'tcx>:
+Printer<
+'tcx,
+Error = fmt::Error,
+Path = Self,
+Region = Self,
+Type = Self,
+DynExistential = Self,
+Const = Self,
+> + fmt::Write1 + fmt::Write2
+{
+//
+}
+pub trait PrettyPrinter<'tcx>:
+fmt::Write + Printer<
+'tcx,
+Error = fmt::Error,
+Path = Self,
+Region = Self,
+Type = Self,
+DynExistential = Self,
+Const = Self,
+>
+{
+//
+}
+pub trait PrettyPrinter<'tcx>:
+fmt::Write + Printer1<
+'tcx,
+Error = fmt::Error,
+Path = Self,
+Region = Self,
+Type = Self,
+DynExistential = Self,
+Const = Self,
+> + Printer2<
+'tcx,
+Error = fmt::Error,
+Path = Self,
+Region = Self,
+Type = Self,
+DynExistential = Self,
+Const = Self,
+>
+{
+//
+}
+
+// Some test cases to ensure other cases formatting were not changed
+fn f() -> Box<
+FnMut() -> Thing<
+WithType = LongItemName,
+Error = LONGLONGLONGLONGLONGONGEvenLongerErrorNameLongerLonger,
+>,
+> {
+}
+fn f() -> Box<
+FnMut() -> Thing<
+WithType = LongItemName,
+Error = LONGLONGLONGLONGLONGONGEvenLongerErrorNameLongerLonger,
+> + fmt::Write1
++ fmt::Write2,
+> {
+}
+
+fn foo<F>(foo2: F)
+where
+F: Fn(
+// this comment is deleted
+)
+{
+}
+fn foo<F>(foo2: F)
+where
+F: Fn(
+// this comment is deleted
+) + fmt::Write
+{
+}
+
+fn elaborate_bounds<F>(mut mk_cand: F)
+where
+F: for<> FnMut(
+&mut ProbeContext<>,
+ty::PolyTraitRefffffffffffffffffffffffffffffffff<>,
+tyyyyyyyyyyyyyyyyyyyyy::AssociatedItem,
+),
+{
+}
+fn elaborate_bounds<F>(mut mk_cand: F)
+where
+F: for<> FnMut(
+&mut ProbeContext<>,
+ty::PolyTraitRefffffffffffffffffffffffffffffffff<>,
+tyyyyyyyyyyyyyyyyyyyyy::AssociatedItem,
+) + fmt::Write,
+{
+}
+
+fn build_sorted_static_get_entry_names(
+mut entries: entryyyyyyyy,
+) -> (
+impl Fn(
+AlphabeticalTraversal,
+Seconddddddddddddddddddddddddddddddddddd
+) -> Parammmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm
++ Sendddddddddddddddddddddddddddddddddddddddddddd
+) {
+}
+    
+pub trait SomeTrait:
+Cloneeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee
++ Eqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq
+{
+}
+
+trait B = where
+for<'b> &'b Self: Send
++ Cloneeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee
++ Copyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy;
diff --git a/src/tools/rustfmt/tests/source/issue-4689/two.rs b/src/tools/rustfmt/tests/source/issue-4689/two.rs
new file mode 100644 (file)
index 0000000..ea7feda
--- /dev/null
@@ -0,0 +1,149 @@
+// rustfmt-version: Two
+
+// Based on the issue description
+pub trait PrettyPrinter<'tcx>:
+Printer<
+'tcx,
+Error = fmt::Error,
+Path = Self,
+Region = Self,
+Type = Self,
+DynExistential = Self,
+Const = Self,
+>
+{
+//
+}
+pub trait PrettyPrinter<'tcx>:
+Printer<
+'tcx,
+Error = fmt::Error,
+Path = Self,
+Region = Self,
+Type = Self,
+DynExistential = Self,
+Const = Self,
+> + fmt::Write
+{
+//
+}
+pub trait PrettyPrinter<'tcx>:
+Printer<
+'tcx,
+Error = fmt::Error,
+Path = Self,
+Region = Self,
+Type = Self,
+DynExistential = Self,
+Const = Self,
+> + fmt::Write1 + fmt::Write2
+{
+//
+}
+pub trait PrettyPrinter<'tcx>:
+fmt::Write + Printer<
+'tcx,
+Error = fmt::Error,
+Path = Self,
+Region = Self,
+Type = Self,
+DynExistential = Self,
+Const = Self,
+>
+{
+//
+}
+pub trait PrettyPrinter<'tcx>:
+fmt::Write + Printer1<
+'tcx,
+Error = fmt::Error,
+Path = Self,
+Region = Self,
+Type = Self,
+DynExistential = Self,
+Const = Self,
+> + Printer2<
+'tcx,
+Error = fmt::Error,
+Path = Self,
+Region = Self,
+Type = Self,
+DynExistential = Self,
+Const = Self,
+>
+{
+//
+}
+
+// Some test cases to ensure other cases formatting were not changed
+fn f() -> Box<
+FnMut() -> Thing<
+WithType = LongItemName,
+Error = LONGLONGLONGLONGLONGONGEvenLongerErrorNameLongerLonger,
+>,
+> {
+}
+fn f() -> Box<
+FnMut() -> Thing<
+WithType = LongItemName,
+Error = LONGLONGLONGLONGLONGONGEvenLongerErrorNameLongerLonger,
+> + fmt::Write1
++ fmt::Write2,
+> {
+}
+
+fn foo<F>(foo2: F)
+where
+F: Fn(
+// this comment is deleted
+)
+{
+}
+fn foo<F>(foo2: F)
+where
+F: Fn(
+// this comment is deleted
+) + fmt::Write
+{
+}
+
+fn elaborate_bounds<F>(mut mk_cand: F)
+where
+F: for<> FnMut(
+&mut ProbeContext<>,
+ty::PolyTraitRefffffffffffffffffffffffffffffffff<>,
+tyyyyyyyyyyyyyyyyyyyyy::AssociatedItem,
+),
+{
+}
+fn elaborate_bounds<F>(mut mk_cand: F)
+where
+F: for<> FnMut(
+&mut ProbeContext<>,
+ty::PolyTraitRefffffffffffffffffffffffffffffffff<>,
+tyyyyyyyyyyyyyyyyyyyyy::AssociatedItem,
+) + fmt::Write,
+{
+}
+
+fn build_sorted_static_get_entry_names(
+mut entries: entryyyyyyyy,
+) -> (
+impl Fn(
+AlphabeticalTraversal,
+Seconddddddddddddddddddddddddddddddddddd
+) -> Parammmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm
++ Sendddddddddddddddddddddddddddddddddddddddddddd
+) {
+}
+    
+pub trait SomeTrait:
+Cloneeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee
++ Eqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq
+{
+}
+
+trait B = where
+for<'b> &'b Self: Send
++ Cloneeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee
++ Copyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy;
diff --git a/src/tools/rustfmt/tests/source/issue_1306.rs b/src/tools/rustfmt/tests/source/issue_1306.rs
new file mode 100644 (file)
index 0000000..03b78e3
--- /dev/null
@@ -0,0 +1,29 @@
+// rustfmt-max_width: 160
+// rustfmt-fn_call_width: 96
+// rustfmt-fn_args_layout: Compressed
+// rustfmt-trailing_comma: Always
+// rustfmt-wrap_comments: true
+
+fn foo() {
+    for elem in try!(gen_epub_book::ops::parse_descriptor_file(&mut try!(File::open(&opts.source_file.1).map_err(|_| {
+        gen_epub_book::Error::Io {
+            desc: "input file",
+            op: "open",
+            more: None,
+        }
+    })),
+                                                               "input file")) {
+        println!("{}", elem);
+    }
+}
+
+fn write_content() {
+    io::copy(try!(File::open(in_f).map_err(|_| {
+        Error::Io {
+            desc: "Content",
+            op: "open",
+            more: None,
+        }
+    })),
+             w);
+}
diff --git a/src/tools/rustfmt/tests/source/issue_3245.rs b/src/tools/rustfmt/tests/source/issue_3245.rs
new file mode 100644 (file)
index 0000000..0279246
--- /dev/null
@@ -0,0 +1,4 @@
+fn main() {
+    let x = 1;
+    ;let y = 3;
+}
diff --git a/src/tools/rustfmt/tests/source/issue_3561.rs b/src/tools/rustfmt/tests/source/issue_3561.rs
new file mode 100644 (file)
index 0000000..8f6cd8f
--- /dev/null
@@ -0,0 +1,6 @@
+fn main() {;7
+}
+
+fn main() {
+    ;7
+}
diff --git a/src/tools/rustfmt/tests/source/skip_macro_invocations/all.rs b/src/tools/rustfmt/tests/source/skip_macro_invocations/all.rs
new file mode 100644 (file)
index 0000000..d0437ee
--- /dev/null
@@ -0,0 +1,11 @@
+// rustfmt-skip_macro_invocations: ["*"]
+
+// Should skip this invocation
+items!(
+        const _: u8 = 0;
+);
+
+// Should skip this invocation
+renamed_items!(
+        const _: u8 = 0;
+);
diff --git a/src/tools/rustfmt/tests/source/skip_macro_invocations/all_and_name.rs b/src/tools/rustfmt/tests/source/skip_macro_invocations/all_and_name.rs
new file mode 100644 (file)
index 0000000..1f67223
--- /dev/null
@@ -0,0 +1,11 @@
+// rustfmt-skip_macro_invocations: ["*","items"]
+
+// Should skip this invocation
+items!(
+        const _: u8 = 0;
+);
+
+// Should also skip this invocation, as the wildcard covers it
+renamed_items!(
+        const _: u8 = 0;
+);
diff --git a/src/tools/rustfmt/tests/source/skip_macro_invocations/empty.rs b/src/tools/rustfmt/tests/source/skip_macro_invocations/empty.rs
new file mode 100644 (file)
index 0000000..f3dd89d
--- /dev/null
@@ -0,0 +1,11 @@
+// rustfmt-skip_macro_invocations: []
+
+// Should not skip this invocation
+items!(
+        const _: u8 = 0;
+);
+
+// Should not skip this invocation
+renamed_items!(
+        const _: u8 = 0;
+);
diff --git a/src/tools/rustfmt/tests/source/skip_macro_invocations/name.rs b/src/tools/rustfmt/tests/source/skip_macro_invocations/name.rs
new file mode 100644 (file)
index 0000000..7fa5d3a
--- /dev/null
@@ -0,0 +1,11 @@
+// rustfmt-skip_macro_invocations: ["items"]
+
+// Should skip this invocation
+items!(
+        const _: u8 = 0;
+);
+
+// Should not skip this invocation
+renamed_items!(
+        const _: u8 = 0;
+);
diff --git a/src/tools/rustfmt/tests/source/skip_macro_invocations/name_unknown.rs b/src/tools/rustfmt/tests/source/skip_macro_invocations/name_unknown.rs
new file mode 100644 (file)
index 0000000..d566953
--- /dev/null
@@ -0,0 +1,6 @@
+// rustfmt-skip_macro_invocations: ["unknown"]
+
+// Should not skip this invocation
+items!(
+        const _: u8 = 0;
+);
diff --git a/src/tools/rustfmt/tests/source/skip_macro_invocations/names.rs b/src/tools/rustfmt/tests/source/skip_macro_invocations/names.rs
new file mode 100644 (file)
index 0000000..a920381
--- /dev/null
@@ -0,0 +1,16 @@
+// rustfmt-skip_macro_invocations: ["foo","bar"]
+
+// Should skip this invocation
+foo!(
+        const _: u8 = 0;
+);
+
+// Should skip this invocation
+bar!(
+        const _: u8 = 0;
+);
+
+// Should not skip this invocation
+baz!(
+        const _: u8 = 0;
+);
diff --git a/src/tools/rustfmt/tests/source/skip_macro_invocations/path_qualified_invocation_mismatch.rs b/src/tools/rustfmt/tests/source/skip_macro_invocations/path_qualified_invocation_mismatch.rs
new file mode 100644 (file)
index 0000000..6129686
--- /dev/null
@@ -0,0 +1,6 @@
+// rustfmt-skip_macro_invocations: ["items"]
+
+// Should not skip this invocation
+self::items!(
+        const _: u8 = 0;
+);
diff --git a/src/tools/rustfmt/tests/source/skip_macro_invocations/path_qualified_match.rs b/src/tools/rustfmt/tests/source/skip_macro_invocations/path_qualified_match.rs
new file mode 100644 (file)
index 0000000..9398918
--- /dev/null
@@ -0,0 +1,6 @@
+// rustfmt-skip_macro_invocations: ["self::items"]
+
+// Should skip this invocation
+self::items!(
+        const _: u8 = 0;
+);
diff --git a/src/tools/rustfmt/tests/source/skip_macro_invocations/path_qualified_name_mismatch.rs b/src/tools/rustfmt/tests/source/skip_macro_invocations/path_qualified_name_mismatch.rs
new file mode 100644 (file)
index 0000000..4e3eb54
--- /dev/null
@@ -0,0 +1,6 @@
+// rustfmt-skip_macro_invocations: ["self::items"]
+
+// Should not skip this invocation
+items!(
+        const _: u8 = 0;
+);
diff --git a/src/tools/rustfmt/tests/source/skip_macro_invocations/use_alias_examples.rs b/src/tools/rustfmt/tests/source/skip_macro_invocations/use_alias_examples.rs
new file mode 100644 (file)
index 0000000..43cb801
--- /dev/null
@@ -0,0 +1,32 @@
+// rustfmt-skip_macro_invocations: ["aaa","ccc"]
+
+// These tests demonstrate a realistic use case with use aliases.
+// The use statements should not impact functionality in any way.
+
+use crate::{aaa, bbb, ddd};
+
+// No use alias, invocation in list
+// Should skip this invocation
+aaa!(
+        const _: u8 = 0;
+);
+
+// Use alias, invocation in list
+// Should skip this invocation
+use crate::bbb as ccc;
+ccc!(
+        const _: u8 = 0;
+);
+
+// Use alias, invocation not in list
+// Should not skip this invocation
+use crate::ddd as eee;
+eee!(
+        const _: u8 = 0;
+);
+
+// No use alias, invocation not in list
+// Should not skip this invocation
+fff!(
+        const _: u8 = 0;
+);
index 9a0f979fbca38b3583d54262f68bac2822f95456..5189a7454f3a7dfb383ba143412a2669207c7835 100644 (file)
@@ -1,4 +1,4 @@
-// Test tuple litterals
+// Test tuple literals
 
 fn foo() {
     let a = (a, a, a, a, a);
index 78b3ce146f2895a5e3a1fc4d0e9891e2aa530e90..56064e4a4cccf9bbe97dbc55054f50fdb5c6e807 100644 (file)
@@ -11,6 +11,6 @@
 ///
 fn foo() {}
 
-/// A long commment for wrapping
+/// A long comment for wrapping
 /// This is a long long long long long long long long long long long long long long long long long long long long sentence.
 fn bar() {}
index 02d5eed1c2923ce759f98ebc7e9869f99f4dca0a..47210cae2aaa0bace3d8e1bd3c31149d148708ad 100644 (file)
@@ -314,7 +314,7 @@ pub enum Feature {
     tbm,
     /// POPCNT (Population Count)
     popcnt,
-    /// FXSR (Floating-point context fast save and restor)
+    /// FXSR (Floating-point context fast save and restore)
     fxsr,
     /// XSAVE (Save Processor Extended States)
     xsave,
diff --git a/src/tools/rustfmt/tests/target/comments_unicode.rs b/src/tools/rustfmt/tests/target/comments_unicode.rs
new file mode 100644 (file)
index 0000000..3e1b6b0
--- /dev/null
@@ -0,0 +1,140 @@
+impl Default for WhitespaceCharacters {
+    fn default() -> Self {
+        Self {
+            space: '·',   // U+00B7
+            nbsp: '⍽',    // U+237D
+            tab: '→',     // U+2192
+            newline: '⏎', // U+23CE
+        }
+    }
+}
+
+const RAINBOWS: &[&str] = &[
+    "rаinЬοѡ", // hue: 0
+    "raіnЬοw", // hue: 2
+    "rаіɴЬow", // hue: 2
+    "raіɴЬoѡ", // hue: 8
+    "ʀainЬow", // hue: 8
+    "ʀaіɴboѡ", // hue: 8
+    "ʀаіnbοw", // hue: 11
+    "rainЬoѡ", // hue: 14
+    "raіɴbow", // hue: 14
+    "rаiɴЬow", // hue: 20
+    "raіnЬow", // hue: 26
+    "ʀaiɴbοw", // hue: 32
+    "raіɴboѡ", // hue: 35
+    "rаiɴbow", // hue: 35
+    "rаіnbοw", // hue: 38
+    "rаinЬow", // hue: 47
+    "ʀaіnboѡ", // hue: 47
+    "ʀaіnЬoѡ", // hue: 47
+    "ʀаіɴbοw", // hue: 53
+    "ʀaіnЬοѡ", // hue: 57
+    "raiɴЬoѡ", // hue: 68
+    "ʀainbοѡ", // hue: 68
+    "ʀаinboѡ", // hue: 68
+    "ʀаiɴbοw", // hue: 68
+    "ʀаіnbow", // hue: 68
+    "rаіnЬοѡ", // hue: 69
+    "ʀainЬοw", // hue: 71
+    "raiɴbow", // hue: 73
+    "raіnЬoѡ", // hue: 74
+    "rаіɴbοw", // hue: 77
+    "raіnЬοѡ", // hue: 81
+    "raiɴЬow", // hue: 83
+    "ʀainbοw", // hue: 83
+    "ʀаinbow", // hue: 83
+    "ʀаiɴbοѡ", // hue: 83
+    "ʀаіnboѡ", // hue: 83
+    "ʀаіɴЬοѡ", // hue: 84
+    "rainЬow", // hue: 85
+    "ʀаiɴЬοw", // hue: 86
+    "ʀаіnbοѡ", // hue: 89
+    "ʀаіnЬοw", // hue: 92
+    "rаiɴbοw", // hue: 95
+    "ʀаіɴbοѡ", // hue: 98
+    "ʀаiɴЬοѡ", // hue: 99
+    "raіnbοw", // hue: 101
+    "ʀаіɴЬοw", // hue: 101
+    "ʀaiɴboѡ", // hue: 104
+    "ʀаinbοѡ", // hue: 104
+    "rаiɴbοѡ", // hue: 107
+    "ʀаinЬοw", // hue: 107
+    "rаiɴЬοw", // hue: 110
+    "rаіnboѡ", // hue: 110
+    "rаіnbοѡ", // hue: 113
+    "ʀainЬοѡ", // hue: 114
+    "rаіnЬοw", // hue: 116
+    "ʀaіɴЬow", // hue: 116
+    "rаinbοw", // hue: 122
+    "ʀаіɴboѡ", // hue: 125
+    "rаinbοѡ", // hue: 131
+    "rainbow", // hue: 134
+    "rаinЬοw", // hue: 134
+    "ʀаiɴboѡ", // hue: 140
+    "rainЬοѡ", // hue: 141
+    "raіɴЬow", // hue: 143
+    "ʀainЬoѡ", // hue: 143
+    "ʀaіɴbow", // hue: 143
+    "ʀainbow", // hue: 148
+    "rаіɴboѡ", // hue: 149
+    "ʀainboѡ", // hue: 155
+    "ʀaіnbow", // hue: 155
+    "ʀaіnЬow", // hue: 155
+    "raiɴbοw", // hue: 158
+    "ʀаiɴЬoѡ", // hue: 158
+    "rainbοw", // hue: 160
+    "rаinbow", // hue: 160
+    "ʀaіɴbοѡ", // hue: 164
+    "ʀаiɴbow", // hue: 164
+    "ʀаіnЬoѡ", // hue: 164
+    "ʀaiɴЬοѡ", // hue: 165
+    "rаiɴboѡ", // hue: 167
+    "ʀaіɴЬοw", // hue: 167
+    "ʀaіɴЬοѡ", // hue: 171
+    "raіnboѡ", // hue: 173
+    "ʀаіɴЬoѡ", // hue: 173
+    "rаіɴbοѡ", // hue: 176
+    "ʀаinЬow", // hue: 176
+    "rаiɴЬοѡ", // hue: 177
+    "rаіɴЬοw", // hue: 179
+    "ʀаinЬoѡ", // hue: 179
+    "ʀаіɴbow", // hue: 179
+    "rаiɴЬoѡ", // hue: 182
+    "raіɴbοѡ", // hue: 188
+    "rаіnЬoѡ", // hue: 188
+    "raiɴЬοѡ", // hue: 189
+    "raіɴЬοw", // hue: 191
+    "ʀaіɴbοw", // hue: 191
+    "ʀаіnЬow", // hue: 191
+    "rainbοѡ", // hue: 194
+    "rаinboѡ", // hue: 194
+    "rаіnbow", // hue: 194
+    "rainЬοw", // hue: 197
+    "rаinЬoѡ", // hue: 206
+    "rаіɴbow", // hue: 206
+    "rаіɴЬοѡ", // hue: 210
+    "ʀaiɴЬow", // hue: 212
+    "raіɴbοw", // hue: 218
+    "rаіnЬow", // hue: 218
+    "ʀaiɴbοѡ", // hue: 221
+    "ʀaiɴЬοw", // hue: 224
+    "ʀaіnbοѡ", // hue: 227
+    "raiɴboѡ", // hue: 230
+    "ʀaіnbοw", // hue: 230
+    "ʀaіnЬοw", // hue: 230
+    "ʀаinЬοѡ", // hue: 231
+    "rainboѡ", // hue: 232
+    "raіnbow", // hue: 232
+    "ʀаіɴЬow", // hue: 233
+    "ʀaіɴЬoѡ", // hue: 239
+    "ʀаіnЬοѡ", // hue: 246
+    "raiɴbοѡ", // hue: 248
+    "ʀаiɴЬow", // hue: 248
+    "raіɴЬοѡ", // hue: 249
+    "raiɴЬοw", // hue: 251
+    "rаіɴЬoѡ", // hue: 251
+    "ʀaiɴbow", // hue: 251
+    "ʀаinbοw", // hue: 251
+    "raіnbοѡ", // hue: 254
+];
diff --git a/src/tools/rustfmt/tests/target/configs/fn_args_layout/compressed.rs b/src/tools/rustfmt/tests/target/configs/fn_args_layout/compressed.rs
deleted file mode 100644 (file)
index f189446..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-// rustfmt-fn_args_layout: Compressed
-// Function arguments density
-
-trait Lorem {
-    fn lorem(ipsum: Ipsum, dolor: Dolor, sit: Sit, amet: Amet);
-
-    fn lorem(ipsum: Ipsum, dolor: Dolor, sit: Sit, amet: Amet) {
-        // body
-    }
-
-    fn lorem(
-        ipsum: Ipsum, dolor: Dolor, sit: Sit, amet: Amet, consectetur: onsectetur,
-        adipiscing: Adipiscing, elit: Elit,
-    );
-
-    fn lorem(
-        ipsum: Ipsum, dolor: Dolor, sit: Sit, amet: Amet, consectetur: onsectetur,
-        adipiscing: Adipiscing, elit: Elit,
-    ) {
-        // body
-    }
-}
diff --git a/src/tools/rustfmt/tests/target/configs/fn_args_layout/tall.rs b/src/tools/rustfmt/tests/target/configs/fn_args_layout/tall.rs
deleted file mode 100644 (file)
index 20f3089..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-// rustfmt-fn_args_layout: Tall
-// Function arguments density
-
-trait Lorem {
-    fn lorem(ipsum: Ipsum, dolor: Dolor, sit: Sit, amet: Amet);
-
-    fn lorem(ipsum: Ipsum, dolor: Dolor, sit: Sit, amet: Amet) {
-        // body
-    }
-
-    fn lorem(
-        ipsum: Ipsum,
-        dolor: Dolor,
-        sit: Sit,
-        amet: Amet,
-        consectetur: onsectetur,
-        adipiscing: Adipiscing,
-        elit: Elit,
-    );
-
-    fn lorem(
-        ipsum: Ipsum,
-        dolor: Dolor,
-        sit: Sit,
-        amet: Amet,
-        consectetur: onsectetur,
-        adipiscing: Adipiscing,
-        elit: Elit,
-    ) {
-        // body
-    }
-}
diff --git a/src/tools/rustfmt/tests/target/configs/fn_args_layout/vertical.rs b/src/tools/rustfmt/tests/target/configs/fn_args_layout/vertical.rs
deleted file mode 100644 (file)
index 6c695a7..0000000
+++ /dev/null
@@ -1,42 +0,0 @@
-// rustfmt-fn_args_layout: Vertical
-// Function arguments density
-
-trait Lorem {
-    fn lorem(
-        ipsum: Ipsum,
-        dolor: Dolor,
-        sit: Sit,
-        amet: Amet,
-    );
-
-    fn lorem(
-        ipsum: Ipsum,
-        dolor: Dolor,
-        sit: Sit,
-        amet: Amet,
-    ) {
-        // body
-    }
-
-    fn lorem(
-        ipsum: Ipsum,
-        dolor: Dolor,
-        sit: Sit,
-        amet: Amet,
-        consectetur: onsectetur,
-        adipiscing: Adipiscing,
-        elit: Elit,
-    );
-
-    fn lorem(
-        ipsum: Ipsum,
-        dolor: Dolor,
-        sit: Sit,
-        amet: Amet,
-        consectetur: onsectetur,
-        adipiscing: Adipiscing,
-        elit: Elit,
-    ) {
-        // body
-    }
-}
diff --git a/src/tools/rustfmt/tests/target/configs/fn_params_layout/compressed.rs b/src/tools/rustfmt/tests/target/configs/fn_params_layout/compressed.rs
new file mode 100644 (file)
index 0000000..ff32f0f
--- /dev/null
@@ -0,0 +1,22 @@
+// rustfmt-fn_params_layout: Compressed
+// Function arguments density
+
+trait Lorem {
+    fn lorem(ipsum: Ipsum, dolor: Dolor, sit: Sit, amet: Amet);
+
+    fn lorem(ipsum: Ipsum, dolor: Dolor, sit: Sit, amet: Amet) {
+        // body
+    }
+
+    fn lorem(
+        ipsum: Ipsum, dolor: Dolor, sit: Sit, amet: Amet, consectetur: onsectetur,
+        adipiscing: Adipiscing, elit: Elit,
+    );
+
+    fn lorem(
+        ipsum: Ipsum, dolor: Dolor, sit: Sit, amet: Amet, consectetur: onsectetur,
+        adipiscing: Adipiscing, elit: Elit,
+    ) {
+        // body
+    }
+}
diff --git a/src/tools/rustfmt/tests/target/configs/fn_params_layout/tall.rs b/src/tools/rustfmt/tests/target/configs/fn_params_layout/tall.rs
new file mode 100644 (file)
index 0000000..25a8679
--- /dev/null
@@ -0,0 +1,32 @@
+// rustfmt-fn_params_layout: Tall
+// Function arguments density
+
+trait Lorem {
+    fn lorem(ipsum: Ipsum, dolor: Dolor, sit: Sit, amet: Amet);
+
+    fn lorem(ipsum: Ipsum, dolor: Dolor, sit: Sit, amet: Amet) {
+        // body
+    }
+
+    fn lorem(
+        ipsum: Ipsum,
+        dolor: Dolor,
+        sit: Sit,
+        amet: Amet,
+        consectetur: onsectetur,
+        adipiscing: Adipiscing,
+        elit: Elit,
+    );
+
+    fn lorem(
+        ipsum: Ipsum,
+        dolor: Dolor,
+        sit: Sit,
+        amet: Amet,
+        consectetur: onsectetur,
+        adipiscing: Adipiscing,
+        elit: Elit,
+    ) {
+        // body
+    }
+}
diff --git a/src/tools/rustfmt/tests/target/configs/fn_params_layout/vertical.rs b/src/tools/rustfmt/tests/target/configs/fn_params_layout/vertical.rs
new file mode 100644 (file)
index 0000000..7a0e424
--- /dev/null
@@ -0,0 +1,42 @@
+// rustfmt-fn_params_layout: Vertical
+// Function arguments density
+
+trait Lorem {
+    fn lorem(
+        ipsum: Ipsum,
+        dolor: Dolor,
+        sit: Sit,
+        amet: Amet,
+    );
+
+    fn lorem(
+        ipsum: Ipsum,
+        dolor: Dolor,
+        sit: Sit,
+        amet: Amet,
+    ) {
+        // body
+    }
+
+    fn lorem(
+        ipsum: Ipsum,
+        dolor: Dolor,
+        sit: Sit,
+        amet: Amet,
+        consectetur: onsectetur,
+        adipiscing: Adipiscing,
+        elit: Elit,
+    );
+
+    fn lorem(
+        ipsum: Ipsum,
+        dolor: Dolor,
+        sit: Sit,
+        amet: Amet,
+        consectetur: onsectetur,
+        adipiscing: Adipiscing,
+        elit: Elit,
+    ) {
+        // body
+    }
+}
index 9a25126b44ecb49888e74c358e95382a822c9528..70fc8ab376ccd9dcdd01d2de55fbd0a7c146bd7a 100644 (file)
@@ -43,7 +43,7 @@ enum StructLikeVariants {
         x: i32, // Test comment
         // Pre-comment
         #[Attr50]
-        y: SomeType, // Aanother Comment
+        y: SomeType, // Another Comment
     },
     SL {
         a: A,
index 2c20ac5a752496b6ef3a1c704eb05f564c3a1de8..f6a1a90c3fc68034d0260cebdd776df1e9b5e1fb 100644 (file)
@@ -1,5 +1,5 @@
 // rustfmt-normalize_comments: true
-// rustfmt-fn_args_layout: Vertical
+// rustfmt-fn_params_layout: Vertical
 // rustfmt-brace_style: AlwaysNextLine
 
 // Case with only one variable.
index 2eb2a973d243d6937d81012efd7308772cc750e0..506d9de34370b0dfaf9415e41cd4647ae4bfe3c2 100644 (file)
@@ -1,4 +1,4 @@
-// rustfmt-fn_args_layout: Compressed
+// rustfmt-fn_params_layout: Compressed
 // Test some of the ways function signatures can be customised.
 
 // Test compressed layout of args.
index da0ac981d872df2f725a46e366783f66c5ffbfd0..bfeca15c967ed0f5c7ee270f674bfc268df1ef40 100644 (file)
@@ -1,4 +1,4 @@
-// rustfmt-fn_args_layout: Vertical
+// rustfmt-fn_params_layout: Vertical
 
 // Empty list should stay on one line.
 fn do_bar() -> u8 {
diff --git a/src/tools/rustfmt/tests/target/issue-2534/format_macro_matchers_false.rs b/src/tools/rustfmt/tests/target/issue-2534/format_macro_matchers_false.rs
new file mode 100644 (file)
index 0000000..2038ed7
--- /dev/null
@@ -0,0 +1,6 @@
+// rustfmt-format_macro_matchers: false
+
+macro_rules! foo {
+    ($a:ident : $b:ty) => {};
+    ($a:ident $b:ident $c:ident) => {};
+}
diff --git a/src/tools/rustfmt/tests/target/issue-2534/format_macro_matchers_true.rs b/src/tools/rustfmt/tests/target/issue-2534/format_macro_matchers_true.rs
new file mode 100644 (file)
index 0000000..01d939a
--- /dev/null
@@ -0,0 +1,6 @@
+// rustfmt-format_macro_matchers: true
+
+macro_rules! foo {
+    ($a:ident : $b:ty) => {};
+    ($a:ident $b:ident $c:ident) => {};
+}
diff --git a/src/tools/rustfmt/tests/target/issue-3987/format_macro_bodies_false.rs b/src/tools/rustfmt/tests/target/issue-3987/format_macro_bodies_false.rs
new file mode 100644 (file)
index 0000000..1352b76
--- /dev/null
@@ -0,0 +1,26 @@
+// rustfmt-format_macro_bodies: false
+
+// with comments
+macro_rules! macros {
+    () => {{
+        Struct {
+            field: (
+                42 + //comment 1
+                42
+                //comment 2
+            ),
+        };
+    }};
+}
+
+// without comments
+macro_rules! macros {
+    () => {{
+        Struct {
+            field: (
+                42 +
+                42
+            ),
+        };
+    }};
+}
diff --git a/src/tools/rustfmt/tests/target/issue-3987/format_macro_bodies_true.rs b/src/tools/rustfmt/tests/target/issue-3987/format_macro_bodies_true.rs
new file mode 100644 (file)
index 0000000..88d5715
--- /dev/null
@@ -0,0 +1,21 @@
+// rustfmt-format_macro_bodies: true
+
+// with comments
+macro_rules! macros {
+    () => {{
+        Struct {
+            field: (
+                42 + //comment 1
+                42
+                //comment 2
+            ),
+        };
+    }};
+}
+
+// without comments
+macro_rules! macros {
+    () => {{
+        Struct { field: (42 + 42) };
+    }};
+}
diff --git a/src/tools/rustfmt/tests/target/issue-4643.rs b/src/tools/rustfmt/tests/target/issue-4643.rs
new file mode 100644 (file)
index 0000000..ef99e4d
--- /dev/null
@@ -0,0 +1,19 @@
+// output doesn't get corrupted when using comments within generic type parameters of a trait
+
+pub trait Something<
+    A,
+    // some comment
+    B,
+    C,
+>
+{
+    fn a(&self, x: A) -> i32;
+    fn b(&self, x: B) -> i32;
+    fn c(&self, x: C) -> i32;
+}
+
+pub trait SomethingElse<A, /* some comment */ B, C> {
+    fn a(&self, x: A) -> i32;
+    fn b(&self, x: B) -> i32;
+    fn c(&self, x: C) -> i32;
+}
diff --git a/src/tools/rustfmt/tests/target/issue-4689/one.rs b/src/tools/rustfmt/tests/target/issue-4689/one.rs
new file mode 100644 (file)
index 0000000..7735e34
--- /dev/null
@@ -0,0 +1,150 @@
+// rustfmt-version: One
+
+// Based on the issue description
+pub trait PrettyPrinter<'tcx>:
+    Printer<
+    'tcx,
+    Error = fmt::Error,
+    Path = Self,
+    Region = Self,
+    Type = Self,
+    DynExistential = Self,
+    Const = Self,
+>
+{
+    //
+}
+pub trait PrettyPrinter<'tcx>:
+    Printer<
+        'tcx,
+        Error = fmt::Error,
+        Path = Self,
+        Region = Self,
+        Type = Self,
+        DynExistential = Self,
+        Const = Self,
+    > + fmt::Write
+{
+    //
+}
+pub trait PrettyPrinter<'tcx>:
+    Printer<
+        'tcx,
+        Error = fmt::Error,
+        Path = Self,
+        Region = Self,
+        Type = Self,
+        DynExistential = Self,
+        Const = Self,
+    > + fmt::Write1
+    + fmt::Write2
+{
+    //
+}
+pub trait PrettyPrinter<'tcx>:
+    fmt::Write
+    + Printer<
+        'tcx,
+        Error = fmt::Error,
+        Path = Self,
+        Region = Self,
+        Type = Self,
+        DynExistential = Self,
+        Const = Self,
+    >
+{
+    //
+}
+pub trait PrettyPrinter<'tcx>:
+    fmt::Write
+    + Printer1<
+        'tcx,
+        Error = fmt::Error,
+        Path = Self,
+        Region = Self,
+        Type = Self,
+        DynExistential = Self,
+        Const = Self,
+    > + Printer2<
+        'tcx,
+        Error = fmt::Error,
+        Path = Self,
+        Region = Self,
+        Type = Self,
+        DynExistential = Self,
+        Const = Self,
+    >
+{
+    //
+}
+
+// Some test cases to ensure other cases formatting were not changed
+fn f() -> Box<
+    FnMut() -> Thing<
+        WithType = LongItemName,
+        Error = LONGLONGLONGLONGLONGONGEvenLongerErrorNameLongerLonger,
+    >,
+> {
+}
+fn f() -> Box<
+    FnMut() -> Thing<
+            WithType = LongItemName,
+            Error = LONGLONGLONGLONGLONGONGEvenLongerErrorNameLongerLonger,
+        > + fmt::Write1
+        + fmt::Write2,
+> {
+}
+
+fn foo<F>(foo2: F)
+where
+    F: Fn(
+        // this comment is deleted
+    ),
+{
+}
+fn foo<F>(foo2: F)
+where
+    F: Fn(
+            // this comment is deleted
+        ) + fmt::Write,
+{
+}
+
+fn elaborate_bounds<F>(mut mk_cand: F)
+where
+    F: FnMut(
+        &mut ProbeContext,
+        ty::PolyTraitRefffffffffffffffffffffffffffffffff,
+        tyyyyyyyyyyyyyyyyyyyyy::AssociatedItem,
+    ),
+{
+}
+fn elaborate_bounds<F>(mut mk_cand: F)
+where
+    F: FnMut(
+            &mut ProbeContext,
+            ty::PolyTraitRefffffffffffffffffffffffffffffffff,
+            tyyyyyyyyyyyyyyyyyyyyy::AssociatedItem,
+        ) + fmt::Write,
+{
+}
+
+fn build_sorted_static_get_entry_names(
+    mut entries: entryyyyyyyy,
+) -> (impl Fn(
+    AlphabeticalTraversal,
+    Seconddddddddddddddddddddddddddddddddddd,
+) -> Parammmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm
+        + Sendddddddddddddddddddddddddddddddddddddddddddd) {
+}
+
+pub trait SomeTrait:
+    Cloneeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee
+    + Eqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq
+{
+}
+
+trait B = where
+    for<'b> &'b Self: Send
+        + Cloneeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee
+        + Copyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy;
diff --git a/src/tools/rustfmt/tests/target/issue-4689/two.rs b/src/tools/rustfmt/tests/target/issue-4689/two.rs
new file mode 100644 (file)
index 0000000..e3b5cd2
--- /dev/null
@@ -0,0 +1,152 @@
+// rustfmt-version: Two
+
+// Based on the issue description
+pub trait PrettyPrinter<'tcx>:
+    Printer<
+        'tcx,
+        Error = fmt::Error,
+        Path = Self,
+        Region = Self,
+        Type = Self,
+        DynExistential = Self,
+        Const = Self,
+    >
+{
+    //
+}
+pub trait PrettyPrinter<'tcx>:
+    Printer<
+        'tcx,
+        Error = fmt::Error,
+        Path = Self,
+        Region = Self,
+        Type = Self,
+        DynExistential = Self,
+        Const = Self,
+    > + fmt::Write
+{
+    //
+}
+pub trait PrettyPrinter<'tcx>:
+    Printer<
+        'tcx,
+        Error = fmt::Error,
+        Path = Self,
+        Region = Self,
+        Type = Self,
+        DynExistential = Self,
+        Const = Self,
+    > + fmt::Write1
+    + fmt::Write2
+{
+    //
+}
+pub trait PrettyPrinter<'tcx>:
+    fmt::Write
+    + Printer<
+        'tcx,
+        Error = fmt::Error,
+        Path = Self,
+        Region = Self,
+        Type = Self,
+        DynExistential = Self,
+        Const = Self,
+    >
+{
+    //
+}
+pub trait PrettyPrinter<'tcx>:
+    fmt::Write
+    + Printer1<
+        'tcx,
+        Error = fmt::Error,
+        Path = Self,
+        Region = Self,
+        Type = Self,
+        DynExistential = Self,
+        Const = Self,
+    > + Printer2<
+        'tcx,
+        Error = fmt::Error,
+        Path = Self,
+        Region = Self,
+        Type = Self,
+        DynExistential = Self,
+        Const = Self,
+    >
+{
+    //
+}
+
+// Some test cases to ensure other cases formatting were not changed
+fn f() -> Box<
+    FnMut() -> Thing<
+        WithType = LongItemName,
+        Error = LONGLONGLONGLONGLONGONGEvenLongerErrorNameLongerLonger,
+    >,
+> {
+}
+fn f() -> Box<
+    FnMut() -> Thing<
+            WithType = LongItemName,
+            Error = LONGLONGLONGLONGLONGONGEvenLongerErrorNameLongerLonger,
+        > + fmt::Write1
+        + fmt::Write2,
+> {
+}
+
+fn foo<F>(foo2: F)
+where
+    F: Fn(
+        // this comment is deleted
+    ),
+{
+}
+fn foo<F>(foo2: F)
+where
+    F: Fn(
+            // this comment is deleted
+        ) + fmt::Write,
+{
+}
+
+fn elaborate_bounds<F>(mut mk_cand: F)
+where
+    F: FnMut(
+        &mut ProbeContext,
+        ty::PolyTraitRefffffffffffffffffffffffffffffffff,
+        tyyyyyyyyyyyyyyyyyyyyy::AssociatedItem,
+    ),
+{
+}
+fn elaborate_bounds<F>(mut mk_cand: F)
+where
+    F: FnMut(
+            &mut ProbeContext,
+            ty::PolyTraitRefffffffffffffffffffffffffffffffff,
+            tyyyyyyyyyyyyyyyyyyyyy::AssociatedItem,
+        ) + fmt::Write,
+{
+}
+
+fn build_sorted_static_get_entry_names(
+    mut entries: entryyyyyyyy,
+) -> (
+    impl Fn(
+        AlphabeticalTraversal,
+        Seconddddddddddddddddddddddddddddddddddd,
+    ) -> Parammmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm
+    + Sendddddddddddddddddddddddddddddddddddddddddddd
+) {
+}
+
+pub trait SomeTrait:
+    Cloneeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee
+    + Eqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq
+{
+}
+
+trait B = where
+    for<'b> &'b Self: Send
+        + Cloneeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee
+        + Copyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy;
index 588656b535fa1af1746da854cc1e64dbb303f06e..29f6bda90631b84efebcea32909a6864305fb1fb 100644 (file)
@@ -1,7 +1,7 @@
 // rustfmt-brace_style: SameLineWhere
 // rustfmt-comment_width: 100
 // rustfmt-edition: 2018
-// rustfmt-fn_args_layout: Compressed
+// rustfmt-fn_params_layout: Compressed
 // rustfmt-hard_tabs: false
 // rustfmt-match_block_trailing_comma: true
 // rustfmt-max_width: 100
diff --git a/src/tools/rustfmt/tests/target/issue-5358.rs b/src/tools/rustfmt/tests/target/issue-5358.rs
new file mode 100644 (file)
index 0000000..d4bf490
--- /dev/null
@@ -0,0 +1,4 @@
+// Test /* comment */ inside trait generics does not get duplicated.
+trait Test</* comment */ T> {}
+
+trait TestTwo</* comment */ T, /* comment */ V> {}
diff --git a/src/tools/rustfmt/tests/target/issue_1306.rs b/src/tools/rustfmt/tests/target/issue_1306.rs
new file mode 100644 (file)
index 0000000..6bb514c
--- /dev/null
@@ -0,0 +1,33 @@
+// rustfmt-max_width: 160
+// rustfmt-fn_call_width: 96
+// rustfmt-fn_args_layout: Compressed
+// rustfmt-trailing_comma: Always
+// rustfmt-wrap_comments: true
+
+fn foo() {
+    for elem in try!(gen_epub_book::ops::parse_descriptor_file(
+        &mut try!(File::open(&opts.source_file.1).map_err(|_| {
+            gen_epub_book::Error::Io {
+                desc: "input file",
+                op: "open",
+                more: None,
+            }
+        })),
+        "input file"
+    )) {
+        println!("{}", elem);
+    }
+}
+
+fn write_content() {
+    io::copy(
+        try!(File::open(in_f).map_err(|_| {
+            Error::Io {
+                desc: "Content",
+                op: "open",
+                more: None,
+            }
+        })),
+        w,
+    );
+}
diff --git a/src/tools/rustfmt/tests/target/issue_3033.rs b/src/tools/rustfmt/tests/target/issue_3033.rs
new file mode 100644 (file)
index 0000000..e12249a
--- /dev/null
@@ -0,0 +1,2 @@
+use dom::bindings::codegen::Bindings::BluetoothRemoteGATTServerBinding::BluetoothRemoteGATTServerBinding::
+    BluetoothRemoteGATTServerMethods;
diff --git a/src/tools/rustfmt/tests/target/issue_3245.rs b/src/tools/rustfmt/tests/target/issue_3245.rs
new file mode 100644 (file)
index 0000000..8f442f1
--- /dev/null
@@ -0,0 +1,4 @@
+fn main() {
+    let x = 1;
+    let y = 3;
+}
diff --git a/src/tools/rustfmt/tests/target/issue_3561.rs b/src/tools/rustfmt/tests/target/issue_3561.rs
new file mode 100644 (file)
index 0000000..846a14d
--- /dev/null
@@ -0,0 +1,7 @@
+fn main() {
+    7
+}
+
+fn main() {
+    7
+}
diff --git a/src/tools/rustfmt/tests/target/issue_4350.rs b/src/tools/rustfmt/tests/target/issue_4350.rs
new file mode 100644 (file)
index 0000000..a94c5c3
--- /dev/null
@@ -0,0 +1,13 @@
+//rustfmt-format_macro_bodies: true
+
+macro_rules! mto_text_left {
+    ($buf:ident, $n:ident, $pos:ident, $state:ident) => {{
+        let cursor = loop {
+            state = match iter.next() {
+                None if $pos == DP::Start => break last_char_idx($buf),
+                None /*some comment */ => break 0,
+            };
+        };
+        Ok(saturate_cursor($buf, cursor))
+    }};
+}
diff --git a/src/tools/rustfmt/tests/target/issue_5668.rs b/src/tools/rustfmt/tests/target/issue_5668.rs
new file mode 100644 (file)
index 0000000..bbd9a53
--- /dev/null
@@ -0,0 +1,8 @@
+type Foo = impl Send;
+struct Struct<
+    const C: usize = {
+        let _: Foo = ();
+        //~^ ERROR: mismatched types
+        0
+    },
+>;
diff --git a/src/tools/rustfmt/tests/target/skip_macro_invocations/all.rs b/src/tools/rustfmt/tests/target/skip_macro_invocations/all.rs
new file mode 100644 (file)
index 0000000..d0437ee
--- /dev/null
@@ -0,0 +1,11 @@
+// rustfmt-skip_macro_invocations: ["*"]
+
+// Should skip this invocation
+items!(
+        const _: u8 = 0;
+);
+
+// Should skip this invocation
+renamed_items!(
+        const _: u8 = 0;
+);
diff --git a/src/tools/rustfmt/tests/target/skip_macro_invocations/all_and_name.rs b/src/tools/rustfmt/tests/target/skip_macro_invocations/all_and_name.rs
new file mode 100644 (file)
index 0000000..1f67223
--- /dev/null
@@ -0,0 +1,11 @@
+// rustfmt-skip_macro_invocations: ["*","items"]
+
+// Should skip this invocation
+items!(
+        const _: u8 = 0;
+);
+
+// Should also skip this invocation, as the wildcard covers it
+renamed_items!(
+        const _: u8 = 0;
+);
diff --git a/src/tools/rustfmt/tests/target/skip_macro_invocations/empty.rs b/src/tools/rustfmt/tests/target/skip_macro_invocations/empty.rs
new file mode 100644 (file)
index 0000000..4a398cc
--- /dev/null
@@ -0,0 +1,11 @@
+// rustfmt-skip_macro_invocations: []
+
+// Should not skip this invocation
+items!(
+    const _: u8 = 0;
+);
+
+// Should not skip this invocation
+renamed_items!(
+    const _: u8 = 0;
+);
diff --git a/src/tools/rustfmt/tests/target/skip_macro_invocations/name.rs b/src/tools/rustfmt/tests/target/skip_macro_invocations/name.rs
new file mode 100644 (file)
index 0000000..c4d5772
--- /dev/null
@@ -0,0 +1,11 @@
+// rustfmt-skip_macro_invocations: ["items"]
+
+// Should skip this invocation
+items!(
+        const _: u8 = 0;
+);
+
+// Should not skip this invocation
+renamed_items!(
+    const _: u8 = 0;
+);
diff --git a/src/tools/rustfmt/tests/target/skip_macro_invocations/name_unknown.rs b/src/tools/rustfmt/tests/target/skip_macro_invocations/name_unknown.rs
new file mode 100644 (file)
index 0000000..7ab1440
--- /dev/null
@@ -0,0 +1,6 @@
+// rustfmt-skip_macro_invocations: ["unknown"]
+
+// Should not skip this invocation
+items!(
+    const _: u8 = 0;
+);
diff --git a/src/tools/rustfmt/tests/target/skip_macro_invocations/names.rs b/src/tools/rustfmt/tests/target/skip_macro_invocations/names.rs
new file mode 100644 (file)
index 0000000..c6b41ff
--- /dev/null
@@ -0,0 +1,16 @@
+// rustfmt-skip_macro_invocations: ["foo","bar"]
+
+// Should skip this invocation
+foo!(
+        const _: u8 = 0;
+);
+
+// Should skip this invocation
+bar!(
+        const _: u8 = 0;
+);
+
+// Should not skip this invocation
+baz!(
+    const _: u8 = 0;
+);
diff --git a/src/tools/rustfmt/tests/target/skip_macro_invocations/path_qualified_invocation_mismatch.rs b/src/tools/rustfmt/tests/target/skip_macro_invocations/path_qualified_invocation_mismatch.rs
new file mode 100644 (file)
index 0000000..6e372c7
--- /dev/null
@@ -0,0 +1,6 @@
+// rustfmt-skip_macro_invocations: ["items"]
+
+// Should not skip this invocation
+self::items!(
+    const _: u8 = 0;
+);
diff --git a/src/tools/rustfmt/tests/target/skip_macro_invocations/path_qualified_match.rs b/src/tools/rustfmt/tests/target/skip_macro_invocations/path_qualified_match.rs
new file mode 100644 (file)
index 0000000..9398918
--- /dev/null
@@ -0,0 +1,6 @@
+// rustfmt-skip_macro_invocations: ["self::items"]
+
+// Should skip this invocation
+self::items!(
+        const _: u8 = 0;
+);
diff --git a/src/tools/rustfmt/tests/target/skip_macro_invocations/path_qualified_name_mismatch.rs b/src/tools/rustfmt/tests/target/skip_macro_invocations/path_qualified_name_mismatch.rs
new file mode 100644 (file)
index 0000000..aa57a2a
--- /dev/null
@@ -0,0 +1,6 @@
+// rustfmt-skip_macro_invocations: ["self::items"]
+
+// Should not skip this invocation
+items!(
+    const _: u8 = 0;
+);
diff --git a/src/tools/rustfmt/tests/target/skip_macro_invocations/use_alias_examples.rs b/src/tools/rustfmt/tests/target/skip_macro_invocations/use_alias_examples.rs
new file mode 100644 (file)
index 0000000..799dd8c
--- /dev/null
@@ -0,0 +1,32 @@
+// rustfmt-skip_macro_invocations: ["aaa","ccc"]
+
+// These tests demonstrate a realistic use case with use aliases.
+// The use statements should not impact functionality in any way.
+
+use crate::{aaa, bbb, ddd};
+
+// No use alias, invocation in list
+// Should skip this invocation
+aaa!(
+        const _: u8 = 0;
+);
+
+// Use alias, invocation in list
+// Should skip this invocation
+use crate::bbb as ccc;
+ccc!(
+        const _: u8 = 0;
+);
+
+// Use alias, invocation not in list
+// Should not skip this invocation
+use crate::ddd as eee;
+eee!(
+    const _: u8 = 0;
+);
+
+// No use alias, invocation not in list
+// Should not skip this invocation
+fff!(
+    const _: u8 = 0;
+);
index 68bb2f3bc2850178937a232ac8d810e91f10e4f3..24fcf8cfd7cf358d25480d6d4d5367816cde9d75 100644 (file)
@@ -1,4 +1,4 @@
-// Test tuple litterals
+// Test tuple literals
 
 fn foo() {
     let a = (a, a, a, a, a);
index d61d4d7c216a309406c9a13a3898766ff151ae6d..6ccecc7e0bbe660a5bb34f527c5a15c4bed86410 100644 (file)
@@ -10,7 +10,7 @@
 /// ```
 fn foo() {}
 
-/// A long commment for wrapping
+/// A long comment for wrapping
 /// This is a long long long long long long long long long long long long long
 /// long long long long long long long sentence.
 fn bar() {}
index bc2edf634de2b617b5f0c46da2c20051f379784c..8ce19c8b5145b818342fa6b5e797ab825bb5bba8 100644 (file)
@@ -59,7 +59,6 @@
     ("cranelift-codegen", "Apache-2.0 WITH LLVM-exception"),
     ("cranelift-codegen-meta", "Apache-2.0 WITH LLVM-exception"),
     ("cranelift-codegen-shared", "Apache-2.0 WITH LLVM-exception"),
-    ("cranelift-egraph", "Apache-2.0 WITH LLVM-exception"),
     ("cranelift-entity", "Apache-2.0 WITH LLVM-exception"),
     ("cranelift-frontend", "Apache-2.0 WITH LLVM-exception"),
     ("cranelift-isle", "Apache-2.0 WITH LLVM-exception"),
     "cranelift-codegen",
     "cranelift-codegen-meta",
     "cranelift-codegen-shared",
-    "cranelift-egraph",
     "cranelift-entity",
     "cranelift-frontend",
     "cranelift-isle",
     "winapi-i686-pc-windows-gnu",
     "winapi-x86_64-pc-windows-gnu",
     "windows-sys",
+    "windows_aarch64_gnullvm",
     "windows_aarch64_msvc",
     "windows_i686_gnu",
     "windows_i686_msvc",
     "windows_x86_64_gnu",
+    "windows_x86_64_gnullvm",
     "windows_x86_64_msvc",
 ];
 
index e9740e30da483d6a5231c8e47a17fe2a678d015a..bc11e1081244ad84017d516a76acf4272afab19a 100644 (file)
@@ -109,3 +109,28 @@ pub unsafe fn transmute_fn_ptr_to_data(x: fn()) -> *const () {
     // as long as it doesn't cause a verifier error by using `bitcast`.
     transmute(x)
 }
+
+pub enum Either<T, U> { A(T), B(U) }
+
+// Previously, we would codegen this as passing/returning a scalar pair of `{ i8, ptr }`,
+// with the `ptr` field representing both `&i32` and `fn()` depending on the variant.
+// This is incorrect, because `fn()` should be `ptr addrspace(1)`, not `ptr`.
+
+// CHECK: define{{.+}}void @should_not_combine_addrspace({{.+\*|ptr}}{{.+}}sret{{.+}}%0, {{.+\*|ptr}}{{.+}}%x)
+#[no_mangle]
+#[inline(never)]
+pub fn should_not_combine_addrspace(x: Either<&i32, fn()>) -> Either<&i32, fn()> {
+    x
+}
+
+// The incorrectness described above would result in us producing (after optimizations)
+// a `ptrtoint`/`inttoptr` roundtrip to convert from `ptr` to `ptr addrspace(1)`.
+
+// CHECK-LABEL: @call_with_fn_ptr
+#[no_mangle]
+pub fn call_with_fn_ptr<'a>(f: fn()) -> Either<&'a i32, fn()> {
+    // CHECK-NOT: ptrtoint
+    // CHECK-NOT: inttoptr
+    // CHECK: call addrspace(1) void @should_not_combine_addrspace
+    should_not_combine_addrspace(Either::B(f))
+}
diff --git a/tests/mir-opt/76803_regression.encode.SimplifyBranchSame.diff b/tests/mir-opt/76803_regression.encode.SimplifyBranchSame.diff
deleted file mode 100644 (file)
index 9780332..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-- // MIR for `encode` before SimplifyBranchSame
-+ // MIR for `encode` after SimplifyBranchSame
-  
-  fn encode(_1: Type) -> Type {
-      debug v => _1;                       // in scope 0 at $DIR/76803_regression.rs:+0:15: +0:16
-      let mut _0: Type;                    // return place in scope 0 at $DIR/76803_regression.rs:+0:27: +0:31
-      let mut _2: isize;                   // in scope 0 at $DIR/76803_regression.rs:+2:9: +2:16
-  
-      bb0: {
-          _2 = discriminant(_1);           // scope 0 at $DIR/76803_regression.rs:+1:11: +1:12
-          switchInt(move _2) -> [0: bb2, otherwise: bb1]; // scope 0 at $DIR/76803_regression.rs:+1:5: +1:12
-      }
-  
-      bb1: {
-          _0 = move _1;                    // scope 0 at $DIR/76803_regression.rs:+3:14: +3:15
-          goto -> bb3;                     // scope 0 at $DIR/76803_regression.rs:+3:14: +3:15
-      }
-  
-      bb2: {
-          Deinit(_0);                      // scope 0 at $DIR/76803_regression.rs:+2:20: +2:27
-          discriminant(_0) = 1;            // scope 0 at $DIR/76803_regression.rs:+2:20: +2:27
-          goto -> bb3;                     // scope 0 at $DIR/76803_regression.rs:+2:20: +2:27
-      }
-  
-      bb3: {
-          return;                          // scope 0 at $DIR/76803_regression.rs:+5:2: +5:2
-      }
-  }
-  
diff --git a/tests/mir-opt/76803_regression.rs b/tests/mir-opt/76803_regression.rs
deleted file mode 100644 (file)
index 05dc3c9..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-// compile-flags: -Z mir-opt-level=1
-// EMIT_MIR 76803_regression.encode.SimplifyBranchSame.diff
-
-#[derive(Debug, Eq, PartialEq)]
-pub enum Type {
-    A,
-    B,
-}
-
-pub fn encode(v: Type) -> Type {
-    match v {
-        Type::A => Type::B,
-        _ => v,
-    }
-}
-
-fn main() {
-    assert_eq!(Type::B, encode(Type::A));
-}
diff --git a/tests/mir-opt/building/custom/arrays.arrays.built.after.mir b/tests/mir-opt/building/custom/arrays.arrays.built.after.mir
new file mode 100644 (file)
index 0000000..4c92127
--- /dev/null
@@ -0,0 +1,14 @@
+// MIR for `arrays` after built
+
+fn arrays() -> usize {
+    let mut _0: usize;                   // return place in scope 0 at $DIR/arrays.rs:+0:32: +0:37
+    let mut _1: [i32; C];                // in scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL
+    let mut _2: usize;                   // in scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL
+
+    bb0: {
+        _1 = [const 5_i32; C];           // scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL
+        _2 = Len(_1);                    // scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL
+        _0 = _2;                         // scope 0 at $DIR/arrays.rs:+4:9: +4:16
+        return;                          // scope 0 at $DIR/arrays.rs:+5:9: +5:17
+    }
+}
diff --git a/tests/mir-opt/building/custom/arrays.rs b/tests/mir-opt/building/custom/arrays.rs
new file mode 100644 (file)
index 0000000..8e0a1fd
--- /dev/null
@@ -0,0 +1,19 @@
+#![feature(custom_mir, core_intrinsics, inline_const)]
+
+extern crate core;
+use core::intrinsics::mir::*;
+
+// EMIT_MIR arrays.arrays.built.after.mir
+#[custom_mir(dialect = "built")]
+fn arrays<const C: usize>() -> usize {
+    mir!({
+        let x = [5_i32; C];
+        let c = Len(x);
+        RET = c;
+        Return()
+    })
+}
+
+fn main() {
+    assert_eq!(arrays::<20>(), 20);
+}
index e5cd456377844e1d18ee1cde5a09ddf26fb828dc..eca5b792ec0a26ebaae0c0d4c1e07d2a2742b726 100644 (file)
@@ -86,6 +86,7 @@ fn switch_option_repr(option: Bool) -> bool {
 #[custom_mir(dialect = "runtime", phase = "initial")]
 fn set_discr(option: &mut Option<()>) {
     mir!({
+        Deinit(*option);
         SetDiscriminant(*option, 0);
         Return()
     })
index 7de9ed0983fe80a2787988eed3e541ae340a86c1..6d07473658acefad878248a707c740c5ec7eb577 100644 (file)
@@ -4,7 +4,8 @@ fn set_discr(_1: &mut Option<()>) -> () {
     let mut _0: ();                      // return place in scope 0 at $DIR/enums.rs:+0:39: +0:39
 
     bb0: {
-        discriminant((*_1)) = 0;         // scope 0 at $DIR/enums.rs:+2:9: +2:36
-        return;                          // scope 0 at $DIR/enums.rs:+3:9: +3:17
+        Deinit((*_1));                   // scope 0 at $DIR/enums.rs:+2:9: +2:24
+        discriminant((*_1)) = 0;         // scope 0 at $DIR/enums.rs:+3:9: +3:36
+        return;                          // scope 0 at $DIR/enums.rs:+4:9: +4:17
     }
 }
diff --git a/tests/mir-opt/building/custom/operators.f.built.after.mir b/tests/mir-opt/building/custom/operators.f.built.after.mir
new file mode 100644 (file)
index 0000000..cb43d5e
--- /dev/null
@@ -0,0 +1,30 @@
+// MIR for `f` after built
+
+fn f(_1: i32, _2: bool) -> i32 {
+    let mut _0: i32;                     // return place in scope 0 at $DIR/operators.rs:+0:30: +0:33
+    let mut _3: (i32, bool);             // in scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL
+
+    bb0: {
+        _1 = Neg(_1);                    // scope 0 at $DIR/operators.rs:+2:9: +2:15
+        _2 = Not(_2);                    // scope 0 at $DIR/operators.rs:+3:9: +3:15
+        _1 = Add(_1, _1);                // scope 0 at $DIR/operators.rs:+4:9: +4:18
+        _1 = Sub(_1, _1);                // scope 0 at $DIR/operators.rs:+5:9: +5:18
+        _1 = Mul(_1, _1);                // scope 0 at $DIR/operators.rs:+6:9: +6:18
+        _1 = Div(_1, _1);                // scope 0 at $DIR/operators.rs:+7:9: +7:18
+        _1 = Rem(_1, _1);                // scope 0 at $DIR/operators.rs:+8:9: +8:18
+        _1 = BitXor(_1, _1);             // scope 0 at $DIR/operators.rs:+9:9: +9:18
+        _1 = BitAnd(_1, _1);             // scope 0 at $DIR/operators.rs:+10:9: +10:18
+        _1 = Shl(_1, _1);                // scope 0 at $DIR/operators.rs:+11:9: +11:19
+        _1 = Shr(_1, _1);                // scope 0 at $DIR/operators.rs:+12:9: +12:19
+        _2 = Eq(_1, _1);                 // scope 0 at $DIR/operators.rs:+13:9: +13:19
+        _2 = Lt(_1, _1);                 // scope 0 at $DIR/operators.rs:+14:9: +14:18
+        _2 = Le(_1, _1);                 // scope 0 at $DIR/operators.rs:+15:9: +15:19
+        _2 = Ge(_1, _1);                 // scope 0 at $DIR/operators.rs:+16:9: +16:19
+        _2 = Gt(_1, _1);                 // scope 0 at $DIR/operators.rs:+17:9: +17:18
+        _3 = CheckedAdd(_1, _1);         // scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL
+        _2 = (_3.1: bool);               // scope 0 at $DIR/operators.rs:+19:9: +19:18
+        _1 = (_3.0: i32);                // scope 0 at $DIR/operators.rs:+20:9: +20:18
+        _0 = _1;                         // scope 0 at $DIR/operators.rs:+21:9: +21:16
+        return;                          // scope 0 at $DIR/operators.rs:+22:9: +22:17
+    }
+}
diff --git a/tests/mir-opt/building/custom/operators.rs b/tests/mir-opt/building/custom/operators.rs
new file mode 100644 (file)
index 0000000..db7a483
--- /dev/null
@@ -0,0 +1,31 @@
+// compile-flags: --crate-type=lib
+#![feature(custom_mir, core_intrinsics, inline_const)]
+use std::intrinsics::mir::*;
+
+// EMIT_MIR operators.f.built.after.mir
+#[custom_mir(dialect = "built")]
+pub fn f(a: i32, b: bool) -> i32 {
+    mir!({
+        a = -a;
+        b = !b;
+        a = a + a;
+        a = a - a;
+        a = a * a;
+        a = a / a;
+        a = a % a;
+        a = a ^ a;
+        a = a & a;
+        a = a << a;
+        a = a >> a;
+        b = a == a;
+        b = a < a;
+        b = a <= a;
+        b = a >= a;
+        b = a > a;
+        let res = Checked(a + a);
+        b = res.1;
+        a = res.0;
+        RET = a;
+        Return()
+    })
+}
diff --git a/tests/mir-opt/intrinsic_asserts.generic.InstCombine.diff b/tests/mir-opt/intrinsic_asserts.generic.InstCombine.diff
new file mode 100644 (file)
index 0000000..8ff64c1
--- /dev/null
@@ -0,0 +1,42 @@
+- // MIR for `generic` before InstCombine
++ // MIR for `generic` after InstCombine
+  
+  fn generic() -> () {
+      let mut _0: ();                      // return place in scope 0 at $DIR/intrinsic_asserts.rs:+0:21: +0:21
+      let _1: ();                          // in scope 0 at $DIR/intrinsic_asserts.rs:+1:5: +1:46
+      let _2: ();                          // in scope 0 at $DIR/intrinsic_asserts.rs:+2:5: +2:47
+      let _3: ();                          // in scope 0 at $DIR/intrinsic_asserts.rs:+3:5: +3:60
+  
+      bb0: {
+          StorageLive(_1);                 // scope 0 at $DIR/intrinsic_asserts.rs:+1:5: +1:46
+          _1 = assert_inhabited::<T>() -> bb1; // scope 0 at $DIR/intrinsic_asserts.rs:+1:5: +1:46
+                                           // mir::Constant
+                                           // + span: $DIR/intrinsic_asserts.rs:25:5: 25:44
+                                           // + literal: Const { ty: extern "rust-intrinsic" fn() {assert_inhabited::<T>}, val: Value(<ZST>) }
+      }
+  
+      bb1: {
+          StorageDead(_1);                 // scope 0 at $DIR/intrinsic_asserts.rs:+1:46: +1:47
+          StorageLive(_2);                 // scope 0 at $DIR/intrinsic_asserts.rs:+2:5: +2:47
+          _2 = assert_zero_valid::<T>() -> bb2; // scope 0 at $DIR/intrinsic_asserts.rs:+2:5: +2:47
+                                           // mir::Constant
+                                           // + span: $DIR/intrinsic_asserts.rs:26:5: 26:45
+                                           // + literal: Const { ty: extern "rust-intrinsic" fn() {assert_zero_valid::<T>}, val: Value(<ZST>) }
+      }
+  
+      bb2: {
+          StorageDead(_2);                 // scope 0 at $DIR/intrinsic_asserts.rs:+2:47: +2:48
+          StorageLive(_3);                 // scope 0 at $DIR/intrinsic_asserts.rs:+3:5: +3:60
+          _3 = assert_mem_uninitialized_valid::<T>() -> bb3; // scope 0 at $DIR/intrinsic_asserts.rs:+3:5: +3:60
+                                           // mir::Constant
+                                           // + span: $DIR/intrinsic_asserts.rs:27:5: 27:58
+                                           // + literal: Const { ty: extern "rust-intrinsic" fn() {assert_mem_uninitialized_valid::<T>}, val: Value(<ZST>) }
+      }
+  
+      bb3: {
+          StorageDead(_3);                 // scope 0 at $DIR/intrinsic_asserts.rs:+3:60: +3:61
+          nop;                             // scope 0 at $DIR/intrinsic_asserts.rs:+0:21: +4:2
+          return;                          // scope 0 at $DIR/intrinsic_asserts.rs:+4:2: +4:2
+      }
+  }
+  
diff --git a/tests/mir-opt/intrinsic_asserts.panics.InstCombine.diff b/tests/mir-opt/intrinsic_asserts.panics.InstCombine.diff
new file mode 100644 (file)
index 0000000..ddc0159
--- /dev/null
@@ -0,0 +1,47 @@
+- // MIR for `panics` before InstCombine
++ // MIR for `panics` after InstCombine
+  
+  fn panics() -> () {
+      let mut _0: ();                      // return place in scope 0 at $DIR/intrinsic_asserts.rs:+0:17: +0:17
+      let _1: ();                          // in scope 0 at $DIR/intrinsic_asserts.rs:+1:5: +1:50
+      let _2: ();                          // in scope 0 at $DIR/intrinsic_asserts.rs:+2:5: +2:49
+      let _3: ();                          // in scope 0 at $DIR/intrinsic_asserts.rs:+3:5: +3:62
+  
+      bb0: {
+          StorageLive(_1);                 // scope 0 at $DIR/intrinsic_asserts.rs:+1:5: +1:50
+-         _1 = assert_inhabited::<Never>() -> bb1; // scope 0 at $DIR/intrinsic_asserts.rs:+1:5: +1:50
++         _1 = assert_inhabited::<Never>(); // scope 0 at $DIR/intrinsic_asserts.rs:+1:5: +1:50
+                                           // mir::Constant
+                                           // + span: $DIR/intrinsic_asserts.rs:17:5: 17:48
+                                           // + literal: Const { ty: extern "rust-intrinsic" fn() {assert_inhabited::<Never>}, val: Value(<ZST>) }
+      }
+  
+      bb1: {
+          StorageDead(_1);                 // scope 0 at $DIR/intrinsic_asserts.rs:+1:50: +1:51
+          StorageLive(_2);                 // scope 0 at $DIR/intrinsic_asserts.rs:+2:5: +2:49
+-         _2 = assert_zero_valid::<&u8>() -> bb2; // scope 0 at $DIR/intrinsic_asserts.rs:+2:5: +2:49
++         _2 = assert_zero_valid::<&u8>(); // scope 0 at $DIR/intrinsic_asserts.rs:+2:5: +2:49
+                                           // mir::Constant
+                                           // + span: $DIR/intrinsic_asserts.rs:18:5: 18:47
+                                           // + user_ty: UserType(0)
+                                           // + literal: Const { ty: extern "rust-intrinsic" fn() {assert_zero_valid::<&u8>}, val: Value(<ZST>) }
+      }
+  
+      bb2: {
+          StorageDead(_2);                 // scope 0 at $DIR/intrinsic_asserts.rs:+2:49: +2:50
+          StorageLive(_3);                 // scope 0 at $DIR/intrinsic_asserts.rs:+3:5: +3:62
+-         _3 = assert_mem_uninitialized_valid::<&u8>() -> bb3; // scope 0 at $DIR/intrinsic_asserts.rs:+3:5: +3:62
++         _3 = assert_mem_uninitialized_valid::<&u8>(); // scope 0 at $DIR/intrinsic_asserts.rs:+3:5: +3:62
+                                           // mir::Constant
+                                           // + span: $DIR/intrinsic_asserts.rs:19:5: 19:60
+                                           // + user_ty: UserType(1)
+                                           // + literal: Const { ty: extern "rust-intrinsic" fn() {assert_mem_uninitialized_valid::<&u8>}, val: Value(<ZST>) }
+      }
+  
+      bb3: {
+          StorageDead(_3);                 // scope 0 at $DIR/intrinsic_asserts.rs:+3:62: +3:63
+          nop;                             // scope 0 at $DIR/intrinsic_asserts.rs:+0:17: +4:2
+          return;                          // scope 0 at $DIR/intrinsic_asserts.rs:+4:2: +4:2
+      }
+  }
+  
diff --git a/tests/mir-opt/intrinsic_asserts.removable.InstCombine.diff b/tests/mir-opt/intrinsic_asserts.removable.InstCombine.diff
new file mode 100644 (file)
index 0000000..568fbf1
--- /dev/null
@@ -0,0 +1,45 @@
+- // MIR for `removable` before InstCombine
++ // MIR for `removable` after InstCombine
+  
+  fn removable() -> () {
+      let mut _0: ();                      // return place in scope 0 at $DIR/intrinsic_asserts.rs:+0:20: +0:20
+      let _1: ();                          // in scope 0 at $DIR/intrinsic_asserts.rs:+1:5: +1:47
+      let _2: ();                          // in scope 0 at $DIR/intrinsic_asserts.rs:+2:5: +2:48
+      let _3: ();                          // in scope 0 at $DIR/intrinsic_asserts.rs:+3:5: +3:61
+  
+      bb0: {
+          StorageLive(_1);                 // scope 0 at $DIR/intrinsic_asserts.rs:+1:5: +1:47
+-         _1 = assert_inhabited::<()>() -> bb1; // scope 0 at $DIR/intrinsic_asserts.rs:+1:5: +1:47
+-                                          // mir::Constant
+-                                          // + span: $DIR/intrinsic_asserts.rs:7:5: 7:45
+-                                          // + literal: Const { ty: extern "rust-intrinsic" fn() {assert_inhabited::<()>}, val: Value(<ZST>) }
++         goto -> bb1;                     // scope 0 at $DIR/intrinsic_asserts.rs:+1:5: +1:47
+      }
+  
+      bb1: {
+          StorageDead(_1);                 // scope 0 at $DIR/intrinsic_asserts.rs:+1:47: +1:48
+          StorageLive(_2);                 // scope 0 at $DIR/intrinsic_asserts.rs:+2:5: +2:48
+-         _2 = assert_zero_valid::<u8>() -> bb2; // scope 0 at $DIR/intrinsic_asserts.rs:+2:5: +2:48
+-                                          // mir::Constant
+-                                          // + span: $DIR/intrinsic_asserts.rs:8:5: 8:46
+-                                          // + literal: Const { ty: extern "rust-intrinsic" fn() {assert_zero_valid::<u8>}, val: Value(<ZST>) }
++         goto -> bb2;                     // scope 0 at $DIR/intrinsic_asserts.rs:+2:5: +2:48
+      }
+  
+      bb2: {
+          StorageDead(_2);                 // scope 0 at $DIR/intrinsic_asserts.rs:+2:48: +2:49
+          StorageLive(_3);                 // scope 0 at $DIR/intrinsic_asserts.rs:+3:5: +3:61
+-         _3 = assert_mem_uninitialized_valid::<u8>() -> bb3; // scope 0 at $DIR/intrinsic_asserts.rs:+3:5: +3:61
+-                                          // mir::Constant
+-                                          // + span: $DIR/intrinsic_asserts.rs:9:5: 9:59
+-                                          // + literal: Const { ty: extern "rust-intrinsic" fn() {assert_mem_uninitialized_valid::<u8>}, val: Value(<ZST>) }
++         goto -> bb3;                     // scope 0 at $DIR/intrinsic_asserts.rs:+3:5: +3:61
+      }
+  
+      bb3: {
+          StorageDead(_3);                 // scope 0 at $DIR/intrinsic_asserts.rs:+3:61: +3:62
+          nop;                             // scope 0 at $DIR/intrinsic_asserts.rs:+0:20: +4:2
+          return;                          // scope 0 at $DIR/intrinsic_asserts.rs:+4:2: +4:2
+      }
+  }
+  
diff --git a/tests/mir-opt/intrinsic_asserts.rs b/tests/mir-opt/intrinsic_asserts.rs
new file mode 100644 (file)
index 0000000..8fb99cd
--- /dev/null
@@ -0,0 +1,28 @@
+#![crate_type = "lib"]
+#![feature(core_intrinsics)]
+
+// All these assertions pass, so all the intrinsic calls should be deleted.
+// EMIT_MIR intrinsic_asserts.removable.InstCombine.diff
+pub fn removable() {
+    core::intrinsics::assert_inhabited::<()>();
+    core::intrinsics::assert_zero_valid::<u8>();
+    core::intrinsics::assert_mem_uninitialized_valid::<u8>();
+}
+
+enum Never {}
+
+// These assertions all diverge, so their target blocks should become None.
+// EMIT_MIR intrinsic_asserts.panics.InstCombine.diff
+pub fn panics() {
+    core::intrinsics::assert_inhabited::<Never>();
+    core::intrinsics::assert_zero_valid::<&u8>();
+    core::intrinsics::assert_mem_uninitialized_valid::<&u8>();
+}
+
+// Whether or not these asserts pass isn't known, so they shouldn't be modified.
+// EMIT_MIR intrinsic_asserts.generic.InstCombine.diff
+pub fn generic<T>() {
+    core::intrinsics::assert_inhabited::<T>();
+    core::intrinsics::assert_zero_valid::<T>();
+    core::intrinsics::assert_mem_uninitialized_valid::<T>();
+}
diff --git a/tests/mir-opt/issue_73223.main.SimplifyArmIdentity.diff b/tests/mir-opt/issue_73223.main.SimplifyArmIdentity.diff
deleted file mode 100644 (file)
index bf3bcfd..0000000
+++ /dev/null
@@ -1,156 +0,0 @@
-- // MIR for `main` before SimplifyArmIdentity
-+ // MIR for `main` after SimplifyArmIdentity
-  
-  fn main() -> () {
-      let mut _0: ();                      // return place in scope 0 at $DIR/issue_73223.rs:+0:11: +0:11
-      let _1: i32;                         // in scope 0 at $DIR/issue_73223.rs:+1:9: +1:14
-      let mut _2: std::option::Option<i32>; // in scope 0 at $DIR/issue_73223.rs:+1:23: +1:30
-      let mut _3: isize;                   // in scope 0 at $DIR/issue_73223.rs:+2:9: +2:16
-      let _4: i32;                         // in scope 0 at $DIR/issue_73223.rs:+2:14: +2:15
-      let mut _6: i32;                     // in scope 0 at $DIR/issue_73223.rs:+6:22: +6:27
-      let mut _7: &i32;                    // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-      let mut _8: &i32;                    // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-      let mut _11: bool;                   // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-      let mut _12: bool;                   // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-      let mut _13: i32;                    // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-      let mut _14: i32;                    // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-      let _16: !;                          // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-      let mut _17: core::panicking::AssertKind; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-      let mut _18: &i32;                   // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-      let _19: &i32;                       // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-      let mut _20: &i32;                   // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-      let _21: &i32;                       // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-      let mut _22: std::option::Option<std::fmt::Arguments<'_>>; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-      let mut _24: &i32;                   // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-      let mut _25: &i32;                   // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-      scope 1 {
-          debug split => _1;               // in scope 1 at $DIR/issue_73223.rs:+1:9: +1:14
-          let _5: std::option::Option<i32>; // in scope 1 at $DIR/issue_73223.rs:+6:9: +6:14
-          scope 3 {
-              debug _prev => _5;           // in scope 3 at $DIR/issue_73223.rs:+6:9: +6:14
-              let _9: &i32;                // in scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-              let _10: &i32;               // in scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-              let mut _23: &i32;           // in scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-              scope 4 {
-                  debug left_val => _9;    // in scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-                  debug right_val => _10;  // in scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-                  let _15: core::panicking::AssertKind; // in scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-                  scope 5 {
-                      debug kind => _15;   // in scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-                  }
-              }
-          }
-      }
-      scope 2 {
-          debug v => _4;                   // in scope 2 at $DIR/issue_73223.rs:+2:14: +2:15
-      }
-  
-      bb0: {
-          StorageLive(_1);                 // scope 0 at $DIR/issue_73223.rs:+1:9: +1:14
-          StorageLive(_2);                 // scope 0 at $DIR/issue_73223.rs:+1:23: +1:30
-          Deinit(_2);                      // scope 0 at $DIR/issue_73223.rs:+1:23: +1:30
-          ((_2 as Some).0: i32) = const 1_i32; // scope 0 at $DIR/issue_73223.rs:+1:23: +1:30
-          discriminant(_2) = 1;            // scope 0 at $DIR/issue_73223.rs:+1:23: +1:30
-          _3 = const 1_isize;              // scope 0 at $DIR/issue_73223.rs:+1:23: +1:30
-          goto -> bb3;                     // scope 0 at $DIR/issue_73223.rs:+1:17: +1:30
-      }
-  
-      bb1: {
-          StorageDead(_2);                 // scope 0 at $DIR/issue_73223.rs:+4:6: +4:7
-          StorageDead(_1);                 // scope 0 at $DIR/issue_73223.rs:+8:1: +8:2
-          return;                          // scope 0 at $DIR/issue_73223.rs:+8:2: +8:2
-      }
-  
-      bb2: {
-          unreachable;                     // scope 0 at $DIR/issue_73223.rs:+1:23: +1:30
-      }
-  
-      bb3: {
-          StorageLive(_4);                 // scope 0 at $DIR/issue_73223.rs:+2:14: +2:15
-          _4 = ((_2 as Some).0: i32);      // scope 0 at $DIR/issue_73223.rs:+2:14: +2:15
-          _1 = _4;                         // scope 2 at $DIR/issue_73223.rs:+2:20: +2:21
-          StorageDead(_4);                 // scope 0 at $DIR/issue_73223.rs:+2:20: +2:21
-          StorageDead(_2);                 // scope 0 at $DIR/issue_73223.rs:+4:6: +4:7
-          StorageLive(_5);                 // scope 1 at $DIR/issue_73223.rs:+6:9: +6:14
-          StorageLive(_6);                 // scope 1 at $DIR/issue_73223.rs:+6:22: +6:27
-          _6 = _1;                         // scope 1 at $DIR/issue_73223.rs:+6:22: +6:27
-          Deinit(_5);                      // scope 1 at $DIR/issue_73223.rs:+6:17: +6:28
-          ((_5 as Some).0: i32) = move _6; // scope 1 at $DIR/issue_73223.rs:+6:17: +6:28
-          discriminant(_5) = 1;            // scope 1 at $DIR/issue_73223.rs:+6:17: +6:28
-          StorageDead(_6);                 // scope 1 at $DIR/issue_73223.rs:+6:27: +6:28
-          StorageLive(_24);                // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          StorageLive(_25);                // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          StorageLive(_7);                 // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          _7 = &_1;                        // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          StorageLive(_8);                 // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          _23 = const _;                   // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-                                           // mir::Constant
-                                           // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL
-                                           // + literal: Const { ty: &i32, val: Unevaluated(main, [], Some(promoted[0])) }
-          _8 = _23;                        // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          Deinit(_24);                     // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          Deinit(_25);                     // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          _24 = move _7;                   // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          _25 = move _8;                   // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          StorageDead(_8);                 // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          StorageDead(_7);                 // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          StorageLive(_9);                 // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          _9 = _24;                        // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          StorageLive(_10);                // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          _10 = _25;                       // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          StorageLive(_11);                // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          StorageLive(_12);                // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          StorageLive(_13);                // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          _13 = (*_9);                     // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          StorageLive(_14);                // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          _14 = const 1_i32;               // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          _12 = Eq(move _13, const 1_i32); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          StorageDead(_14);                // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          StorageDead(_13);                // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          _11 = Not(move _12);             // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          StorageDead(_12);                // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          switchInt(move _11) -> [0: bb5, otherwise: bb4]; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-      }
-  
-      bb4: {
-          StorageLive(_15);                // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          Deinit(_15);                     // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          discriminant(_15) = 0;           // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          StorageLive(_16);                // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          StorageLive(_17);                // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          _17 = const core::panicking::AssertKind::Eq; // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-                                           // mir::Constant
-                                           // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL
-                                           // + literal: Const { ty: core::panicking::AssertKind, val: Value(Scalar(0x00)) }
-          StorageLive(_18);                // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          StorageLive(_19);                // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          _19 = _9;                        // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          _18 = _19;                       // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          StorageLive(_20);                // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          StorageLive(_21);                // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          _21 = _10;                       // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          _20 = _21;                       // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          StorageLive(_22);                // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          Deinit(_22);                     // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          discriminant(_22) = 0;           // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          _16 = core::panicking::assert_failed::<i32, i32>(const core::panicking::AssertKind::Eq, move _18, move _20, move _22); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-                                           // mir::Constant
-                                           // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL
-                                           // + literal: Const { ty: for<'a, 'b, 'c> fn(core::panicking::AssertKind, &'a i32, &'b i32, Option<Arguments<'c>>) -> ! {core::panicking::assert_failed::<i32, i32>}, val: Value(<ZST>) }
-                                           // mir::Constant
-                                           // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL
-                                           // + literal: Const { ty: core::panicking::AssertKind, val: Value(Scalar(0x00)) }
-      }
-  
-      bb5: {
-          StorageDead(_11);                // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          StorageDead(_10);                // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          StorageDead(_9);                 // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          StorageDead(_24);                // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          StorageDead(_25);                // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          StorageDead(_5);                 // scope 1 at $DIR/issue_73223.rs:+8:1: +8:2
-          StorageDead(_1);                 // scope 0 at $DIR/issue_73223.rs:+8:1: +8:2
-          return;                          // scope 0 at $DIR/issue_73223.rs:+8:2: +8:2
-      }
-  }
-  
diff --git a/tests/mir-opt/issue_73223.rs b/tests/mir-opt/issue_73223.rs
deleted file mode 100644 (file)
index be114ca..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-fn main() {
-    let split = match Some(1) {
-        Some(v) => v,
-        None => return,
-    };
-
-    let _prev = Some(split);
-    assert_eq!(split, 1);
-}
-
-
-// EMIT_MIR issue_73223.main.SimplifyArmIdentity.diff
index 3af37955f238079de77ae656b08b2694d33ba5ba..60fddb630d964d72bfdcbb0b32c0bb768a192e54 100644 (file)
@@ -8,6 +8,4 @@ extern crate std;
 // pretty-mode:expanded
 // pp-exact:dollar-crate.pp
 
-fn main() {
-    { ::std::io::_print(::core::fmt::Arguments::new_v1(&["rust\n"], &[])); };
-}
+fn main() { { ::std::io::_print(format_args!("rust\n")); }; }
index 18e6d75b1d5ad05a60a3d87f3e33a29d4618ab12..44d21625a2d108a2e14e966d2e14328215adfa7b 100644 (file)
@@ -32,7 +32,7 @@ fn bar() ({
         ({
                 let res =
                     ((::alloc::fmt::format as
-                            for<'a> fn(Arguments<'a>) -> String {format})(((::core::fmt::Arguments::new_v1
+                            for<'a> fn(Arguments<'a>) -> String {format})(((<#[lang = "format_arguments"]>::new_v1
                                 as
                                 fn(&[&'static str], &[ArgumentV1<'_>]) -> Arguments<'_> {Arguments::<'_>::new_v1})((&([("test"
                                             as &str)] as [&str; 1]) as &[&str; 1]),
index 1831ab38fab49d9728505491e3d15e4e9b653773..44cda0d3d117f8bfec9ff71bea889ee811153ba2 100644 (file)
@@ -254,12 +254,12 @@ unpacked-remapped-single:
        $(RUSTC) $(UNSTABLEOPTS) -C split-debuginfo=unpacked -C debuginfo=2 \
                -Z split-dwarf-kind=single --remap-path-prefix $(TMPDIR)=/a foo.rs -g
        objdump -Wi $(TMPDIR)/foo | grep DW_AT_GNU_dwo_name | (! grep $(TMPDIR)) || exit 1
-       ls $(TMPDIR)/*.o
+       rm $(TMPDIR)/*.o
        ls $(TMPDIR)/*.dwo && exit 1 || exit 0
        ls $(TMPDIR)/*.dwp && exit 1 || exit 0
        rm $(TMPDIR)/$(call BIN,foo)
 
-unpacked-crosscrate: packed-crosscrate-split packed-crosscrate-single
+unpacked-crosscrate: unpacked-crosscrate-split unpacked-crosscrate-single
 
 # - Debuginfo in `.dwo` files
 # - (bar) `.rlib` file created, contains `.dwo`
diff --git a/tests/run-make/overwrite-input/Makefile b/tests/run-make/overwrite-input/Makefile
new file mode 100644 (file)
index 0000000..03b03eb
--- /dev/null
@@ -0,0 +1,13 @@
+include ../../run-make-fulldeps/tools.mk
+
+all:
+       $(RUSTC) main.rs -o main.rs 2> $(TMPDIR)/file.stderr || echo "failed successfully"
+       $(RUSTC) main.rs -o . 2> $(TMPDIR)/folder.stderr || echo "failed successfully"
+
+ifdef RUSTC_BLESS_TEST
+       cp "$(TMPDIR)"/file.stderr file.stderr
+       cp "$(TMPDIR)"/folder.stderr folder.stderr
+else
+       $(DIFF) file.stderr "$(TMPDIR)"/file.stderr
+       $(DIFF) folder.stderr "$(TMPDIR)"/folder.stderr
+endif
diff --git a/tests/run-make/overwrite-input/file.stderr b/tests/run-make/overwrite-input/file.stderr
new file mode 100644 (file)
index 0000000..9936962
--- /dev/null
@@ -0,0 +1,6 @@
+warning: ignoring --out-dir flag due to -o flag
+
+error: the input file "main.rs" would be overwritten by the generated executable
+
+error: aborting due to previous error; 1 warning emitted
+
diff --git a/tests/run-make/overwrite-input/folder.stderr b/tests/run-make/overwrite-input/folder.stderr
new file mode 100644 (file)
index 0000000..81b1e73
--- /dev/null
@@ -0,0 +1,6 @@
+warning: ignoring --out-dir flag due to -o flag
+
+error: the generated executable for the input file "main.rs" conflicts with the existing directory "."
+
+error: aborting due to previous error; 1 warning emitted
+
diff --git a/tests/run-make/overwrite-input/main.rs b/tests/run-make/overwrite-input/main.rs
new file mode 100644 (file)
index 0000000..f328e4d
--- /dev/null
@@ -0,0 +1 @@
+fn main() {}
diff --git a/tests/run-make/overwrite-input/main.stderr b/tests/run-make/overwrite-input/main.stderr
new file mode 100644 (file)
index 0000000..9936962
--- /dev/null
@@ -0,0 +1,6 @@
+warning: ignoring --out-dir flag due to -o flag
+
+error: the input file "main.rs" would be overwritten by the generated executable
+
+error: aborting due to previous error; 1 warning emitted
+
index 895864d89445fdfe85f57d799e276818d0517f5f..3e444cbd6dc9985bcab38905b01d3e62f9fa6cb8 100644 (file)
@@ -28,7 +28,7 @@ goto: "file://" + |DOC_PATH| + "/settings.html"
 size: (400, 600)
 // Ignored for now https://github.com/rust-lang/rust/issues/93784.
 // compare-elements-position-near-false: (
-//     "#preferred-light-theme .setting-name",
-//     "#preferred-light-theme .choice",
+//     "#preferred-light-theme .setting-radio-name",
+//     "#preferred-light-theme .setting-radio",
 //     {"y": 16},
 // )
index 419cc5ebac35de6325566ccb8d8501c998fa31fb..a84172885780856b3927b12a212ceb2666f9da68 100644 (file)
@@ -43,12 +43,12 @@ wait-for: "#settings"
 // We check that the "Use system theme" is disabled.
 assert-property: ("#theme-system-preference", {"checked": "false"})
 // Meaning that only the "theme" menu is showing up.
-assert: ".setting-line:not(.hidden) #theme"
-assert: ".setting-line.hidden #preferred-dark-theme"
-assert: ".setting-line.hidden #preferred-light-theme"
+assert: "#theme.setting-line:not(.hidden)"
+assert: "#preferred-dark-theme.setting-line.hidden"
+assert: "#preferred-light-theme.setting-line.hidden"
 
 // We check that the correct theme is selected.
-assert-property: ("#theme .choices #theme-dark", {"checked": "true"})
+assert-property: ("#theme .setting-radio-choices #theme-dark", {"checked": "true"})
 
 // Some style checks...
 move-cursor-to: "#settings-menu > a"
@@ -109,31 +109,31 @@ assert-css: (
         "box-shadow": "rgb(33, 150, 243) 0px 0px 1px 1px",
     },
 )
-// Now we check the setting-name for radio buttons is on a different line than the label.
+// Now we check the setting-radio-name is on a different line than the label.
 compare-elements-position-near: (
-    "#theme .setting-name",
-    "#theme .choices",
+    "#theme .setting-radio-name",
+    "#theme .setting-radio-choices",
     {"x": 1}
 )
 compare-elements-position-near-false: (
-    "#theme .setting-name",
-    "#theme .choices",
+    "#theme .setting-radio-name",
+    "#theme .setting-radio-choices",
     {"y": 1}
 )
 // Now we check that the label positions are all on the same line.
 compare-elements-position-near: (
-    "#theme .choices #theme-light",
-    "#theme .choices #theme-dark",
+    "#theme .setting-radio-choices #theme-light",
+    "#theme .setting-radio-choices #theme-dark",
     {"y": 1}
 )
 compare-elements-position-near: (
-    "#theme .choices #theme-dark",
-    "#theme .choices #theme-ayu",
+    "#theme .setting-radio-choices #theme-dark",
+    "#theme .setting-radio-choices #theme-ayu",
     {"y": 1}
 )
 compare-elements-position-near: (
-    "#theme .choices #theme-ayu",
-    "#theme .choices #theme-system-preference",
+    "#theme .setting-radio-choices #theme-ayu",
+    "#theme .setting-radio-choices #theme-system-preference",
     {"y": 1}
 )
 
@@ -180,17 +180,17 @@ assert-css: (
 // We now switch the display.
 click: "#theme-system-preference"
 // Wait for the hidden element to show up.
-wait-for: ".setting-line:not(.hidden) #preferred-dark-theme"
-assert: ".setting-line:not(.hidden) #preferred-light-theme"
+wait-for: "#preferred-dark-theme.setting-line:not(.hidden)"
+assert: "#preferred-light-theme.setting-line:not(.hidden)"
 
 // We check their text as well.
-assert-text: ("#preferred-dark-theme .setting-name", "Preferred dark theme")
-assert-text: ("#preferred-light-theme .setting-name", "Preferred light theme")
+assert-text: ("#preferred-dark-theme .setting-radio-name", "Preferred dark theme")
+assert-text: ("#preferred-light-theme .setting-radio-name", "Preferred light theme")
 
 // We now check that clicking on the toggles' text is like clicking on the checkbox.
 // To test it, we use the "Disable keyboard shortcuts".
 local-storage: {"rustdoc-disable-shortcuts": "false"}
-click: ".setting-line:last-child .settings-toggle .label"
+click: ".setting-line:last-child .setting-check span"
 assert-local-storage: {"rustdoc-disable-shortcuts": "true"}
 
 // Make sure that "Disable keyboard shortcuts" actually took effect.
@@ -200,7 +200,7 @@ assert-false: "#help-button .popover"
 wait-for-css: ("#settings-menu .popover", {"display": "block"})
 
 // Now turn keyboard shortcuts back on, and see if they work.
-click: ".setting-line:last-child .settings-toggle .label"
+click: ".setting-line:last-child .setting-check span"
 assert-local-storage: {"rustdoc-disable-shortcuts": "false"}
 press-key: "Escape"
 press-key: "?"
index cc47f1f450c5a79b65b8c7527ef3ba97e769c278..31c9d99aa832491b76ffc8af89b79c6ba91c76b5 100644 (file)
@@ -43,7 +43,7 @@ assert-local-storage: { "rustdoc-theme": "ayu" }
 
 assert-local-storage-false: { "rustdoc-use-system-theme": "true" }
 click: "#theme-system-preference"
-wait-for: ".setting-line:not(.hidden) #preferred-light-theme"
+wait-for: "#preferred-light-theme.setting-line:not(.hidden)"
 assert-local-storage: { "rustdoc-use-system-theme": "true" }
 // We click on both preferred light and dark themes to be sure that there is a change.
 click: "#preferred-light-theme-dark"
@@ -52,16 +52,16 @@ wait-for-css: ("body", { "background-color": |background_dark| })
 
 reload:
 // Ensure that the "preferred themes" are still displayed.
-wait-for: ".setting-line:not(.hidden) #preferred-light-theme"
+wait-for: "#preferred-light-theme.setting-line:not(.hidden)"
 click: "#theme-light"
 wait-for-css: ("body", { "background-color": |background_light| })
 assert-local-storage: { "rustdoc-theme": "light" }
 // Ensure it's now hidden again
-wait-for: ".setting-line.hidden #preferred-light-theme"
+wait-for: "#preferred-light-theme.setting-line.hidden"
 // And ensure the theme was rightly set.
 wait-for-css: ("body", { "background-color": |background_light| })
 assert-local-storage: { "rustdoc-theme": "light" }
 
 reload:
 wait-for: "#settings"
-assert: ".setting-line.hidden #preferred-light-theme"
+assert: "#preferred-light-theme.setting-line.hidden"
index 20bde549a037807f3f0351828177b1e6006899d4..eeb22878f3c63f7c6f4fd1da7e361f5a8f2bcfdb 100644 (file)
@@ -1,4 +1,4 @@
 <div class="item-decl"><pre class="rust"><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),
+    Borrowed(<a class="primitive" href="{{channel}}/std/primitive.reference.html">&amp;'a B</a>),
     Whatever(<a class="primitive" href="{{channel}}/std/primitive.u32.html">u32</a>),
 }</code></pre></div>
\ No newline at end of file
index d9fc0c22309dbc97f4f8c3fdd469bf676063e65f..c8037c2a8df5a946527d14945c30514be80c0418 100644 (file)
@@ -1,4 +1,4 @@
 <div class="item-decl"><pre class="rust"><code>pub enum Cow2&lt;'a, B:&#160;?<a class="trait" href="{{channel}}/core/marker/trait.Sized.html" title="trait core::marker::Sized">Sized</a> + <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&gt; {
-    Borrowed(<a class="primitive" href="{{channel}}/std/primitive.reference.html">&amp;'a </a>B),
+    Borrowed(<a class="primitive" href="{{channel}}/std/primitive.reference.html">&amp;'a B</a>),
     Whatever(<a class="primitive" href="{{channel}}/std/primitive.u32.html">u32</a>),
 }</code></pre></div>
\ No newline at end of file
index f375265d7c183ff57963f75bee1a1f136f2bf82e..5892270b2f9309aa04495227d0f921c6d539fbbc 100644 (file)
@@ -1,4 +1,4 @@
 <div class="item-decl"><pre class="rust"><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 a: <a class="primitive" href="{{channel}}/std/primitive.reference.html">&amp;'a B</a>,
     pub b: <a class="primitive" href="{{channel}}/std/primitive.u32.html">u32</a>,
 }</code></pre></div>
\ No newline at end of file
index 1c59962eb1c58e1b75c0082fb48ec72b065422e6..d3952b0c56699eecd68e68005bb243b737d82285 100644 (file)
@@ -1,4 +1,4 @@
 <div class="item-decl"><pre class="rust"><code>pub struct Struct2&lt;'a, B:&#160;?<a class="trait" href="{{channel}}/core/marker/trait.Sized.html" title="trait core::marker::Sized">Sized</a> + <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&gt; {
-    pub a: <a class="primitive" href="{{channel}}/std/primitive.reference.html">&amp;'a </a>B,
+    pub a: <a class="primitive" href="{{channel}}/std/primitive.reference.html">&amp;'a B</a>,
     pub b: <a class="primitive" href="{{channel}}/std/primitive.u32.html">u32</a>,
 }</code></pre></div>
\ No newline at end of file
index 4299688221a8b3d1498f18a2719b8ac75d26c123..47897dc003a433d8de2a2f5b77d08e345ac68836 100644 (file)
@@ -1,6 +1,8 @@
 error[E0597]: `arena` does not live long enough
   --> $DIR/dropck-tarena-cycle-checked.rs:116:7
    |
+LL |     let arena = TypedArena::default();
+   |         ----- binding `arena` declared here
 LL |     f(&arena);
    |       ^^^^^^ borrowed value does not live long enough
 LL | }
index ccffee9cdbda97c9270914bf91c553266b6e72d8..493d74b0bdec9f8e6c42e4665d1db5befbd9f154 100644 (file)
@@ -1,6 +1,8 @@
 error[E0597]: `arena` does not live long enough
   --> $DIR/dropck-tarena-unsound-drop.rs:41:7
    |
+LL |     let arena: TypedArena<C> = TypedArena::default();
+   |         ----- binding `arena` declared here
 LL |     f(&arena);
    |       ^^^^^^ borrowed value does not live long enough
 LL | }
index c97cd171b1e38610578588cb1c5363d142741cae..b5ecb3e1b56fb28147755ab50302952063669a0e 100644 (file)
@@ -2,9 +2,9 @@ error[E0506]: cannot assign to `a` because it is borrowed
   --> $DIR/type-check-4.rs:14:9
    |
 LL |         let p = &a;
-   |                 -- borrow of `a` occurs here
+   |                 -- `a` is borrowed here
 LL |         asm!("{}", out(reg) a);
-   |         ^^^^^^^^^^^^^^^^^^^^^^ assignment to borrowed `a` occurs here
+   |         ^^^^^^^^^^^^^^^^^^^^^^ `a` is assigned to here but it was already borrowed
 LL |
 LL |         println!("{}", p);
    |                        - borrow later used here
@@ -13,7 +13,7 @@ error[E0503]: cannot use `a` because it was mutably borrowed
   --> $DIR/type-check-4.rs:22:28
    |
 LL |         let p = &mut a;
-   |                 ------ borrow of `a` occurs here
+   |                 ------ `a` is borrowed here
 LL |         asm!("{}", in(reg) a);
    |                            ^ use of borrowed `a`
 LL |
index 840e33b4b8a8e900cedd6b87f1794cfd10434097..2fe3f2d4a02505149a1dbb347b9314c00500b908 100644 (file)
@@ -1,6 +1,9 @@
 error[E0505]: cannot move out of `x` because it is borrowed
   --> $DIR/associated-types-outlives.rs:22:14
    |
+LL |                     F: for<'a> FnOnce(<T as Foo<'a>>::Bar)>(x: T, f: F) {
+   |                                                             - binding `x` declared here
+...
 LL |         's: loop { y = denormalise(&x); break }
    |                                    -- borrow of `x` occurs here
 LL |         drop(x);
index 505751969b623168fdc168c8ce5829c194300cdd..f263809552fdf3d88a0af7c0cadc9238a85b2ab8 100644 (file)
@@ -44,4 +44,18 @@ impl AssocConst for () {
     const C: Self::Ty = 0u8;
 }
 
+pub trait Trait {
+    type Res = isize; //~ NOTE associated type defaults can't be assumed inside the trait defining them
+
+    fn infer_me_correctly() -> Self::Res {
+        //~^ NOTE expected `<Self as Trait>::Res` because of return type
+
+        // {integer} == isize
+        2
+        //~^ ERROR mismatched types
+        //~| NOTE expected associated type, found integer
+        //~| NOTE expected associated type `<Self as Trait>::Res`
+    }
+}
+
 fn main() {}
index 71d421926e702f0b0b3a4786833392ff1f3a9c37..bdcfadd3955d26d39632304f4e2cd5cd245bb125 100644 (file)
@@ -24,6 +24,21 @@ LL |     const C: Self::Ty = 0u8;
    = note: expected associated type `<Self as AssocConst>::Ty`
                          found type `u8`
 
-error: aborting due to 2 previous errors
+error[E0308]: mismatched types
+  --> $DIR/defaults-in-other-trait-items.rs:54:9
+   |
+LL |     type Res = isize;
+   |     ----------------- associated type defaults can't be assumed inside the trait defining them
+LL |
+LL |     fn infer_me_correctly() -> Self::Res {
+   |                                --------- expected `<Self as Trait>::Res` because of return type
+...
+LL |         2
+   |         ^ expected associated type, found integer
+   |
+   = note: expected associated type `<Self as Trait>::Res`
+                         found type `{integer}`
+
+error: aborting due to 3 previous errors
 
 For more information about this error, try `rustc --explain E0308`.
index 74411008c9dda6f74a2a64cb1dd13247d6dd4dc0..977620d9052f271b37244490edf6d8c311cdaf21 100644 (file)
@@ -1,13 +1,13 @@
 error[E0308]: mismatched types
   --> $DIR/issue-26681.rs:17:39
    |
+LL |     type Fv: Foo = u8;
+   |     ------------------ associated type defaults can't be assumed inside the trait defining them
 LL |     const C: <Self::Fv as Foo>::Bar = 6665;
    |                                       ^^^^ expected associated type, found integer
    |
    = note: expected associated type `<<Self as Baz>::Fv as Foo>::Bar`
                          found type `{integer}`
-   = help: consider constraining the associated type `<<Self as Baz>::Fv as Foo>::Bar` to `{integer}`
-   = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html
 
 error: aborting due to previous error
 
index f2802698fd5b646fdd3e993df175ae58705b5abe..bd648de30672d8b9057c725594688aaad5331ce8 100644 (file)
@@ -5,6 +5,7 @@ LL |     require_send(send_fut);
    |                  ^^^^^^^^ future created by async block is not `Send`
    |
    = help: the trait `Sync` is not implemented for `RefCell<i32>`
+   = note: if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` instead
 note: future is not `Send` as it awaits another future which is not `Send`
   --> $DIR/issue-68112.rs:34:17
    |
@@ -23,6 +24,7 @@ LL |     require_send(send_fut);
    |                  ^^^^^^^^ future created by async block is not `Send`
    |
    = help: the trait `Sync` is not implemented for `RefCell<i32>`
+   = note: if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` instead
 note: future is not `Send` as it awaits another future which is not `Send`
   --> $DIR/issue-68112.rs:43:17
    |
@@ -43,6 +45,7 @@ LL |     require_send(send_fut);
    |     required by a bound introduced by this call
    |
    = help: the trait `Sync` is not implemented for `RefCell<i32>`
+   = note: if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` instead
    = note: required for `Arc<RefCell<i32>>` to implement `Send`
 note: required because it's used within this `async fn` body
   --> $DIR/issue-68112.rs:50:31
index 38eb85b302fd588abbeb8e8f4b82f84338fa21bb..35b7341f63a4ddfc5040d3785abfb226773827ca 100644 (file)
@@ -5,6 +5,7 @@ LL |     require_send(send_fut);
    |                  ^^^^^^^^ future created by async block is not `Send`
    |
    = help: the trait `Sync` is not implemented for `RefCell<i32>`
+   = note: if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` instead
 note: future is not `Send` as it awaits another future which is not `Send`
   --> $DIR/issue-68112.rs:34:17
    |
@@ -23,6 +24,7 @@ LL |     require_send(send_fut);
    |                  ^^^^^^^^ future created by async block is not `Send`
    |
    = help: the trait `Sync` is not implemented for `RefCell<i32>`
+   = note: if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` instead
 note: future is not `Send` as it awaits another future which is not `Send`
   --> $DIR/issue-68112.rs:43:17
    |
@@ -43,6 +45,7 @@ LL |     require_send(send_fut);
    |     required by a bound introduced by this call
    |
    = help: the trait `Sync` is not implemented for `RefCell<i32>`
+   = note: if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` instead
    = note: required for `Arc<RefCell<i32>>` to implement `Send`
 note: required because it's used within this `async fn` body
   --> $DIR/issue-68112.rs:50:31
index b96cab9f0f51affffcac89671167a6490b5cc134..628ba1a4818936642e68726a80c6af74cab267b4 100644 (file)
@@ -4,9 +4,9 @@ error[E0506]: cannot assign to `*x` because it is borrowed
 LL | pub async fn async_fn(x: &mut i32) -> &i32 {
    |                          - let's call the lifetime of this reference `'1`
 LL |     let y = &*x;
-   |             --- borrow of `*x` occurs here
+   |             --- `*x` is borrowed here
 LL |     *x += 1;
-   |     ^^^^^^^ assignment to borrowed `*x` occurs here
+   |     ^^^^^^^ `*x` is assigned to here but it was already borrowed
 LL |     y
    |     - returning this value requires that `*x` is borrowed for `'1`
 
@@ -14,9 +14,9 @@ error[E0506]: cannot assign to `*x` because it is borrowed
   --> $DIR/issue-74072-lifetime-name-annotations.rs:16:9
    |
 LL |         let y = &*x;
-   |                 --- borrow of `*x` occurs here
+   |                 --- `*x` is borrowed here
 LL |         *x += 1;
-   |         ^^^^^^^ assignment to borrowed `*x` occurs here
+   |         ^^^^^^^ `*x` is assigned to here but it was already borrowed
 LL |         y
    |         - returning this value requires that `*x` is borrowed for `'1`
 LL |     })()
@@ -28,9 +28,9 @@ error[E0506]: cannot assign to `*x` because it is borrowed
 LL |     (async move || -> &i32 {
    |                       - let's call the lifetime of this reference `'1`
 LL |         let y = &*x;
-   |                 --- borrow of `*x` occurs here
+   |                 --- `*x` is borrowed here
 LL |         *x += 1;
-   |         ^^^^^^^ assignment to borrowed `*x` occurs here
+   |         ^^^^^^^ `*x` is assigned to here but it was already borrowed
 LL |         y
    |         - returning this value requires that `*x` is borrowed for `'1`
 
@@ -38,9 +38,9 @@ error[E0506]: cannot assign to `*x` because it is borrowed
   --> $DIR/issue-74072-lifetime-name-annotations.rs:32:9
    |
 LL |         let y = &*x;
-   |                 --- borrow of `*x` occurs here
+   |                 --- `*x` is borrowed here
 LL |         *x += 1;
-   |         ^^^^^^^ assignment to borrowed `*x` occurs here
+   |         ^^^^^^^ `*x` is assigned to here but it was already borrowed
 LL |         y
    |         - returning this value requires that `*x` is borrowed for `'1`
 LL |     }
index 3b731d9c60a6ae20b51e776fc86dc88cd4468fc0..b69033a0eda0b836a84c154b599565cbb1b07ddf 100644 (file)
@@ -4,9 +4,9 @@ error[E0506]: cannot assign to `*x` because it is borrowed
 LL | pub async fn async_fn(x: &mut i32) -> (&i32, &i32) {
    |                          - let's call the lifetime of this reference `'1`
 LL |     let y = &*x;
-   |             --- borrow of `*x` occurs here
+   |             --- `*x` is borrowed here
 LL |     *x += 1;
-   |     ^^^^^^^ assignment to borrowed `*x` occurs here
+   |     ^^^^^^^ `*x` is assigned to here but it was already borrowed
 LL |     (&32, y)
    |     -------- returning this value requires that `*x` is borrowed for `'1`
 
index d86e84033b8cd688191c48f0926dc1ea2256da36..a599ac1d92f831386d1bdb146f952d0e6388523d 100644 (file)
@@ -2,9 +2,9 @@ error[E0506]: cannot assign to `a` because it is borrowed
   --> $DIR/ret-ref.rs:16:5
    |
 LL |     let future = multiple_named_lifetimes(&a, &b);
-   |                                           -- borrow of `a` occurs here
+   |                                           -- `a` is borrowed here
 LL |     a += 1;
-   |     ^^^^^^ assignment to borrowed `a` occurs here
+   |     ^^^^^^ `a` is assigned to here but it was already borrowed
 LL |     b += 1;
 LL |     let p = future.await;
    |             ------ borrow later used here
@@ -13,10 +13,10 @@ error[E0506]: cannot assign to `b` because it is borrowed
   --> $DIR/ret-ref.rs:17:5
    |
 LL |     let future = multiple_named_lifetimes(&a, &b);
-   |                                               -- borrow of `b` occurs here
+   |                                               -- `b` is borrowed here
 LL |     a += 1;
 LL |     b += 1;
-   |     ^^^^^^ assignment to borrowed `b` occurs here
+   |     ^^^^^^ `b` is assigned to here but it was already borrowed
 LL |     let p = future.await;
    |             ------ borrow later used here
 
@@ -24,10 +24,10 @@ error[E0506]: cannot assign to `a` because it is borrowed
   --> $DIR/ret-ref.rs:28:5
    |
 LL |     let future = multiple_named_lifetimes(&a, &b);
-   |                                           -- borrow of `a` occurs here
+   |                                           -- `a` is borrowed here
 LL |     let p = future.await;
 LL |     a += 1;
-   |     ^^^^^^ assignment to borrowed `a` occurs here
+   |     ^^^^^^ `a` is assigned to here but it was already borrowed
 LL |     b += 1;
 LL |     drop(p);
    |          - borrow later used here
index 1b776322aaa647c24a32645894483ac651ac2a93..aaa8b169583fd667d723ea93d733ccd262f66ee3 100644 (file)
@@ -15,12 +15,7 @@ LL | bug!();
    |
    = note: this error originates in the macro `bug` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error: unexpected expression: `{
-               let res =
-                   ::alloc::fmt::format(::core::fmt::Arguments::new_v1(&[""],
-                           &[::core::fmt::ArgumentV1::new_display(&"u8")]));
-               res
-           }.as_str()`
+error: unexpected expression: `{ let res = ::alloc::fmt::format(format_args!("{0}", "u8")); res }.as_str()`
   --> $DIR/key-value-expansion.rs:48:23
    |
 LL |         doc_comment! {format!("{coor}", coor = stringify!($t1)).as_str()}
index 20c7fb3a98395bddc9bf07788364b7630dd9d867..bd2435a78bf222152d8a6653e574e2a69ce5e1db 100644 (file)
@@ -9,7 +9,7 @@ fn add_assign(&mut self, _: Int) {
 }
 
 fn main() {
-    let mut x = Int(1);
+    let mut x = Int(1); //~ NOTE binding `x` declared here
     x
     //~^ NOTE borrow of `x` occurs here
     +=
index 2910c910d55241bf4c660f667df359b0ac38289f..d1096aea2794e3db0f8f9359ec674e388561ae8d 100644 (file)
@@ -1,6 +1,8 @@
 error[E0505]: cannot move out of `x` because it is borrowed
   --> $DIR/augmented-assignments.rs:16:5
    |
+LL |     let mut x = Int(1);
+   |         ----- binding `x` declared here
 LL |     x
    |     - borrow of `x` occurs here
 ...
index dae267da05d1758bd31791fff00a437cc3066a8a..8645169b98ac9d2a227e33dcb092468243afc54b 100644 (file)
@@ -41,6 +41,8 @@ LL | fn move_then_borrow<T: Add<Output=()> + Clone + Copy>(x: T) {
 error[E0505]: cannot move out of `x` because it is borrowed
   --> $DIR/binop-move-semantics.rs:21:5
    |
+LL | fn move_borrowed<T: Add<Output=()>>(x: T, mut y: T) {
+   |                                     - binding `x` declared here
 LL |     let m = &x;
    |             -- borrow of `x` occurs here
 ...
@@ -53,6 +55,9 @@ LL |     use_mut(n); use_imm(m);
 error[E0505]: cannot move out of `y` because it is borrowed
   --> $DIR/binop-move-semantics.rs:23:5
    |
+LL | fn move_borrowed<T: Add<Output=()>>(x: T, mut y: T) {
+   |                                           ----- binding `y` declared here
+LL |     let m = &x;
 LL |     let n = &mut y;
    |             ------ borrow of `y` occurs here
 ...
index 50eee1049db6e479e2c827046b8f484927995f4c..5835f06753bb11242967e095fead9a0a55b747b6 100644 (file)
@@ -4,8 +4,8 @@ error: cannot borrow value as mutable because it is also borrowed as immutable
 LL |         ref foo @ [.., ref mut bar] => (),
    |         -------^^^^^^^^-----------^
    |         |              |
-   |         |              mutable borrow, by `bar`, occurs here
-   |         immutable borrow, by `foo`, occurs here
+   |         |              value is mutably borrowed by `bar` here
+   |         value is borrowed by `foo` here
 
 error: cannot borrow value as mutable because it is also borrowed as immutable
   --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:120:9
@@ -13,8 +13,8 @@ error: cannot borrow value as mutable because it is also borrowed as immutable
 LL |         ref foo @ Some(box ref mut s) => (),
    |         -------^^^^^^^^^^^^---------^
    |         |                  |
-   |         |                  mutable borrow, by `s`, occurs here
-   |         immutable borrow, by `foo`, occurs here
+   |         |                  value is mutably borrowed by `s` here
+   |         value is borrowed by `foo` here
 
 error[E0382]: borrow of moved value: `x`
   --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:18:5
index befa751a6007b49c39a9530b025ccd59b7b46c75..d7d3efe492cef715f078077547b4df9193fd1081 100644 (file)
@@ -1,6 +1,8 @@
 error[E0505]: cannot move out of `x` because it is borrowed
   --> $DIR/borrow-tuple-fields.rs:12:13
    |
+LL |     let x: (Box<_>, _) = (Box::new(1), 2);
+   |         - binding `x` declared here
 LL |     let r = &x.0;
    |             ---- borrow of `x.0` occurs here
 LL |     let y = x;
@@ -32,6 +34,8 @@ LL |     a.use_ref();
 error[E0505]: cannot move out of `x` because it is borrowed
   --> $DIR/borrow-tuple-fields.rs:28:13
    |
+LL |     let x = Foo(Box::new(1), 2);
+   |         - binding `x` declared here
 LL |     let r = &x.0;
    |             ---- borrow of `x.0` occurs here
 LL |     let y = x;
index 98f6f00a7d48bbdb6a725d0af80d535854020fea..c1d668f74efb94354e7b63c90bf9d503747d6331 100644 (file)
@@ -2,7 +2,7 @@ error[E0503]: cannot use `y` because it was mutably borrowed
   --> $DIR/borrowck-anon-fields-variant.rs:16:19
    |
 LL |       Foo::Y(ref mut a, _) => a,
-   |              --------- borrow of `y.0` occurs here
+   |              --------- `y.0` is borrowed here
 ...
 LL |     let b = match y {
    |                   ^ use of borrowed `y.0`
@@ -14,7 +14,7 @@ error[E0503]: cannot use `y` because it was mutably borrowed
   --> $DIR/borrowck-anon-fields-variant.rs:34:19
    |
 LL |       Foo::Y(ref mut a, _) => a,
-   |              --------- borrow of `y.0` occurs here
+   |              --------- `y.0` is borrowed here
 ...
 LL |     let b = match y {
    |                   ^ use of borrowed `y.0`
index 2b7cef7b3253b55fb5febe33969f66ca0b1119f5..d35f2331a76f4ed06b2c3593a4f1bce997962e32 100644 (file)
@@ -2,10 +2,10 @@ error[E0506]: cannot assign to `p.x` because it is borrowed
   --> $DIR/borrowck-assign-comp.rs:10:5
    |
 LL |     let q = &p;
-   |             -- borrow of `p.x` occurs here
+   |             -- `p.x` is borrowed here
 ...
 LL |     p.x = 5;
-   |     ^^^^^^^ assignment to borrowed `p.x` occurs here
+   |     ^^^^^^^ `p.x` is assigned to here but it was already borrowed
 LL |     q.x;
    |     --- borrow later used here
 
@@ -13,9 +13,9 @@ error[E0506]: cannot assign to `p` because it is borrowed
   --> $DIR/borrowck-assign-comp.rs:20:5
    |
 LL |     let q = &p.y;
-   |             ---- borrow of `p` occurs here
+   |             ---- `p` is borrowed here
 LL |     p = Point {x: 5, y: 7};
-   |     ^^^^^^^^^^^^^^^^^^^^^^ assignment to borrowed `p` occurs here
+   |     ^^^^^^^^^^^^^^^^^^^^^^ `p` is assigned to here but it was already borrowed
 LL |     p.x; // silence warning
 LL |     *q; // stretch loan
    |     -- borrow later used here
@@ -24,9 +24,9 @@ error[E0506]: cannot assign to `p.y` because it is borrowed
   --> $DIR/borrowck-assign-comp.rs:31:5
    |
 LL |     let q = &p.y;
-   |             ---- borrow of `p.y` occurs here
+   |             ---- `p.y` is borrowed here
 LL |     p.y = 5;
-   |     ^^^^^^^ assignment to borrowed `p.y` occurs here
+   |     ^^^^^^^ `p.y` is assigned to here but it was already borrowed
 LL |     *q;
    |     -- borrow later used here
 
index 0b21d113f74ee7c72e3e298c402a61c5193b8f50..8c0a8efcc1828548bfc810f2e36b5fe0a32be634 100644 (file)
@@ -2,7 +2,7 @@ error[E0503]: cannot use `*y.pointer` because it was mutably borrowed
   --> $DIR/borrowck-assign-to-andmut-in-borrowed-loc.rs:18:9
    |
 LL |         let z = copy_borrowed_ptr(&mut y);
-   |                                   ------ borrow of `y` occurs here
+   |                                   ------ `y` is borrowed here
 LL |         *y.pointer += 1;
    |         ^^^^^^^^^^^^^^^ use of borrowed `y`
 ...
@@ -13,9 +13,9 @@ error[E0506]: cannot assign to `*y.pointer` because it is borrowed
   --> $DIR/borrowck-assign-to-andmut-in-borrowed-loc.rs:18:9
    |
 LL |         let z = copy_borrowed_ptr(&mut y);
-   |                                   ------ borrow of `*y.pointer` occurs here
+   |                                   ------ `*y.pointer` is borrowed here
 LL |         *y.pointer += 1;
-   |         ^^^^^^^^^^^^^^^ assignment to borrowed `*y.pointer` occurs here
+   |         ^^^^^^^^^^^^^^^ `*y.pointer` is assigned to here but it was already borrowed
 ...
 LL |         *z.pointer += 1;
    |         --------------- borrow later used here
index 371bcf2b69cf847d1b6d0b912a7875a4e529c30f..e582ec605defee89b1a051f391d39d66f4833cfe 100644 (file)
@@ -1,6 +1,9 @@
 error[E0505]: cannot move out of `a` because it is borrowed
   --> $DIR/borrowck-bad-nested-calls-move.rs:25:9
    |
+LL |     let mut a: Box<_> = Box::new(1);
+   |         ----- binding `a` declared here
+...
 LL |     add(
    |     --- borrow later used by call
 LL |         &*a,
@@ -11,6 +14,8 @@ LL |         a);
 error[E0505]: cannot move out of `a` because it is borrowed
   --> $DIR/borrowck-bad-nested-calls-move.rs:32:9
    |
+LL |     let mut a: Box<_> = Box::new(1);
+   |         ----- binding `a` declared here
 LL |     add(
    |     --- borrow later used by call
 LL |         &*a,
index fadcd11a592aa7444c98852e6d9ce31b28f1a35a..8a7870e0c44af17949deeaf46bbfd92bc66f59c8 100644 (file)
@@ -49,9 +49,9 @@ error[E0506]: cannot assign to `x` because it is borrowed
 LL |     let c2 = || x * 5;
    |              -- - borrow occurs due to use in closure
    |              |
-   |              borrow of `x` occurs here
+   |              `x` is borrowed here
 LL |     x = 5;
-   |     ^^^^^ assignment to borrowed `x` occurs here
+   |     ^^^^^ `x` is assigned to here but it was already borrowed
 LL |
 LL |     drop(c2);
    |          -- borrow later used here
@@ -62,9 +62,9 @@ error[E0506]: cannot assign to `x` because it is borrowed
 LL |     let c1 = || get(&x);
    |              --      - borrow occurs due to use in closure
    |              |
-   |              borrow of `x` occurs here
+   |              `x` is borrowed here
 LL |     x = 5;
-   |     ^^^^^ assignment to borrowed `x` occurs here
+   |     ^^^^^ `x` is assigned to here but it was already borrowed
 LL |
 LL |     drop(c1);
    |          -- borrow later used here
@@ -75,9 +75,9 @@ error[E0506]: cannot assign to `*x` because it is borrowed
 LL |     let c1 = || get(&*x);
    |              --      -- borrow occurs due to use in closure
    |              |
-   |              borrow of `*x` occurs here
+   |              `*x` is borrowed here
 LL |     *x = 5;
-   |     ^^^^^^ assignment to borrowed `*x` occurs here
+   |     ^^^^^^ `*x` is assigned to here but it was already borrowed
 LL |
 LL |     drop(c1);
    |          -- borrow later used here
@@ -88,9 +88,9 @@ error[E0506]: cannot assign to `*x.f` because it is borrowed
 LL |     let c1 = || get(&*x.f);
    |              --      ---- borrow occurs due to use in closure
    |              |
-   |              borrow of `*x.f` occurs here
+   |              `*x.f` is borrowed here
 LL |     *x.f = 5;
-   |     ^^^^^^^^ assignment to borrowed `*x.f` occurs here
+   |     ^^^^^^^^ `*x.f` is assigned to here but it was already borrowed
 LL |
 LL |     drop(c1);
    |          -- borrow later used here
index 2c1b9c10d4660dc0cd71e3931f2224d2dd9592a5..cb29c9fdac3c66bd356a81d0d5076f35c520dab3 100644 (file)
@@ -45,7 +45,7 @@ error[E0503]: cannot use `f.x` because it was mutably borrowed
   --> $DIR/borrowck-describe-lvalue.rs:37:9
    |
 LL |         let x = f.x();
-   |                 ----- borrow of `f` occurs here
+   |                 ----- `f` is borrowed here
 LL |         f.x;
    |         ^^^ use of borrowed `f`
 LL |         drop(x);
@@ -55,7 +55,7 @@ error[E0503]: cannot use `g.0` because it was mutably borrowed
   --> $DIR/borrowck-describe-lvalue.rs:44:9
    |
 LL |         let x = g.x();
-   |                 ----- borrow of `g` occurs here
+   |                 ----- `g` is borrowed here
 LL |         g.0;
    |         ^^^ use of borrowed `g`
 LL |         drop(x);
@@ -65,7 +65,7 @@ error[E0503]: cannot use `h.0` because it was mutably borrowed
   --> $DIR/borrowck-describe-lvalue.rs:51:9
    |
 LL |         let x = &mut h.0;
-   |                 -------- borrow of `h.0` occurs here
+   |                 -------- `h.0` is borrowed here
 LL |         h.0;
    |         ^^^ use of borrowed `h.0`
 LL |         drop(x);
@@ -75,7 +75,7 @@ error[E0503]: cannot use `e.0` because it was mutably borrowed
   --> $DIR/borrowck-describe-lvalue.rs:59:20
    |
 LL |         let x = e.x();
-   |                 ----- borrow of `e` occurs here
+   |                 ----- `e` is borrowed here
 LL |         match e {
 LL |             Baz::X(value) => value
    |                    ^^^^^ use of borrowed `e`
@@ -87,7 +87,7 @@ error[E0503]: cannot use `u.a` because it was mutably borrowed
   --> $DIR/borrowck-describe-lvalue.rs:67:9
    |
 LL |         let x = &mut u.a;
-   |                 -------- borrow of `u.a` occurs here
+   |                 -------- `u.a` is borrowed here
 LL |         u.a;
    |         ^^^ use of borrowed `u.a`
 LL |         drop(x);
@@ -97,7 +97,7 @@ error[E0503]: cannot use `f.x` because it was mutably borrowed
   --> $DIR/borrowck-describe-lvalue.rs:74:9
    |
 LL |         let x = f.x();
-   |                 ----- borrow of `*f` occurs here
+   |                 ----- `*f` is borrowed here
 LL |         f.x;
    |         ^^^ use of borrowed `*f`
 LL |         drop(x);
@@ -107,7 +107,7 @@ error[E0503]: cannot use `g.0` because it was mutably borrowed
   --> $DIR/borrowck-describe-lvalue.rs:81:9
    |
 LL |         let x = g.x();
-   |                 ----- borrow of `*g` occurs here
+   |                 ----- `*g` is borrowed here
 LL |         g.0;
    |         ^^^ use of borrowed `*g`
 LL |         drop(x);
@@ -117,7 +117,7 @@ error[E0503]: cannot use `h.0` because it was mutably borrowed
   --> $DIR/borrowck-describe-lvalue.rs:88:9
    |
 LL |         let x = &mut h.0;
-   |                 -------- borrow of `h.0` occurs here
+   |                 -------- `h.0` is borrowed here
 LL |         h.0;
    |         ^^^ use of borrowed `h.0`
 LL |         drop(x);
@@ -127,7 +127,7 @@ error[E0503]: cannot use `e.0` because it was mutably borrowed
   --> $DIR/borrowck-describe-lvalue.rs:96:20
    |
 LL |         let x = e.x();
-   |                 ----- borrow of `*e` occurs here
+   |                 ----- `*e` is borrowed here
 LL |         match *e {
 LL |             Baz::X(value) => value
    |                    ^^^^^ use of borrowed `*e`
@@ -139,7 +139,7 @@ error[E0503]: cannot use `u.a` because it was mutably borrowed
   --> $DIR/borrowck-describe-lvalue.rs:105:9
    |
 LL |         let x = &mut u.a;
-   |                 -------- borrow of `u.a` occurs here
+   |                 -------- `u.a` is borrowed here
 LL |         u.a;
    |         ^^^ use of borrowed `u.a`
 LL |         drop(x);
@@ -149,7 +149,7 @@ error[E0503]: cannot use `v[..]` because it was mutably borrowed
   --> $DIR/borrowck-describe-lvalue.rs:113:15
    |
 LL |         let x = &mut v;
-   |                 ------ borrow of `v` occurs here
+   |                 ------ `v` is borrowed here
 LL |         match v {
 LL |             &[x, _, .., _, _] => println!("{}", x),
    |               ^ use of borrowed `v`
@@ -161,7 +161,7 @@ error[E0503]: cannot use `v[..]` because it was mutably borrowed
   --> $DIR/borrowck-describe-lvalue.rs:118:18
    |
 LL |         let x = &mut v;
-   |                 ------ borrow of `v` occurs here
+   |                 ------ `v` is borrowed here
 ...
 LL |             &[_, x, .., _, _] => println!("{}", x),
    |                  ^ use of borrowed `v`
@@ -173,7 +173,7 @@ error[E0503]: cannot use `v[..]` because it was mutably borrowed
   --> $DIR/borrowck-describe-lvalue.rs:123:25
    |
 LL |         let x = &mut v;
-   |                 ------ borrow of `v` occurs here
+   |                 ------ `v` is borrowed here
 ...
 LL |             &[_, _, .., x, _] => println!("{}", x),
    |                         ^ use of borrowed `v`
@@ -185,7 +185,7 @@ error[E0503]: cannot use `v[..]` because it was mutably borrowed
   --> $DIR/borrowck-describe-lvalue.rs:128:28
    |
 LL |         let x = &mut v;
-   |                 ------ borrow of `v` occurs here
+   |                 ------ `v` is borrowed here
 ...
 LL |             &[_, _, .., _, x] => println!("{}", x),
    |                            ^ use of borrowed `v`
@@ -197,7 +197,7 @@ error[E0503]: cannot use `v[..]` because it was mutably borrowed
   --> $DIR/borrowck-describe-lvalue.rs:139:15
    |
 LL |         let x = &mut v;
-   |                 ------ borrow of `v` occurs here
+   |                 ------ `v` is borrowed here
 LL |         match v {
 LL |             &[x @ ..] => println!("{:?}", x),
    |               ^ use of borrowed `v`
@@ -209,7 +209,7 @@ error[E0503]: cannot use `v[..]` because it was mutably borrowed
   --> $DIR/borrowck-describe-lvalue.rs:144:18
    |
 LL |         let x = &mut v;
-   |                 ------ borrow of `v` occurs here
+   |                 ------ `v` is borrowed here
 ...
 LL |             &[_, x @ ..] => println!("{:?}", x),
    |                  ^ use of borrowed `v`
@@ -221,7 +221,7 @@ error[E0503]: cannot use `v[..]` because it was mutably borrowed
   --> $DIR/borrowck-describe-lvalue.rs:149:15
    |
 LL |         let x = &mut v;
-   |                 ------ borrow of `v` occurs here
+   |                 ------ `v` is borrowed here
 ...
 LL |             &[x @ .., _] => println!("{:?}", x),
    |               ^ use of borrowed `v`
@@ -233,7 +233,7 @@ error[E0503]: cannot use `v[..]` because it was mutably borrowed
   --> $DIR/borrowck-describe-lvalue.rs:154:18
    |
 LL |         let x = &mut v;
-   |                 ------ borrow of `v` occurs here
+   |                 ------ `v` is borrowed here
 ...
 LL |             &[_, x @ .., _] => println!("{:?}", x),
    |                  ^ use of borrowed `v`
@@ -245,7 +245,7 @@ error[E0503]: cannot use `e` because it was mutably borrowed
   --> $DIR/borrowck-describe-lvalue.rs:166:15
    |
 LL |         let x = &mut e;
-   |                 ------ borrow of `e` occurs here
+   |                 ------ `e` is borrowed here
 LL |         match e {
    |               ^ use of borrowed `e`
 ...
@@ -304,7 +304,7 @@ error[E0503]: cannot use `*v` because it was mutably borrowed
   --> $DIR/borrowck-describe-lvalue.rs:232:9
    |
 LL |         let x = &mut v;
-   |                 ------ borrow of `v` occurs here
+   |                 ------ `v` is borrowed here
 LL |         v[0].y;
    |         ^^^^ use of borrowed `v`
 ...
@@ -315,7 +315,7 @@ error[E0503]: cannot use `v[_].y` because it was mutably borrowed
   --> $DIR/borrowck-describe-lvalue.rs:232:9
    |
 LL |         let x = &mut v;
-   |                 ------ borrow of `v` occurs here
+   |                 ------ `v` is borrowed here
 LL |         v[0].y;
    |         ^^^^^^ use of borrowed `v`
 ...
index e009f5913edd072c2026c35721bb3edd000e6cf9..11812847dd1813a45c57ef9f15b332a66ae05776 100644 (file)
@@ -41,6 +41,8 @@ LL |     let p = &x.b;
 error[E0505]: cannot move out of `x.b` because it is borrowed
   --> $DIR/borrowck-field-sensitivity.rs:34:10
    |
+LL |     let x = A { a: 1, b: Box::new(2) };
+   |         - binding `x` declared here
 LL |     let p = &x.b;
    |             ---- borrow of `x.b` occurs here
 LL |     drop(x.b);
@@ -51,6 +53,8 @@ LL |     drop(**p);
 error[E0505]: cannot move out of `x.b` because it is borrowed
   --> $DIR/borrowck-field-sensitivity.rs:41:14
    |
+LL |     let x = A { a: 1, b: Box::new(2) };
+   |         - binding `x` declared here
 LL |     let p = &x.b;
    |             ---- borrow of `x.b` occurs here
 LL |     let _y = A { a: 3, .. x };
index a66db05ccc5fcfe7c6ba59917551cf972f7a1b23..1a20ec85fc00f07add55ee4ed182a74ddb9c3b54 100644 (file)
@@ -2,10 +2,10 @@ error[E0506]: cannot assign to `_a` because it is borrowed
   --> $DIR/borrowck-imm-ref-to-mut-rec-field-issue-3162-c.rs:6:9
    |
 LL |     let b = &mut _a;
-   |             ------- borrow of `_a` occurs here
+   |             ------- `_a` is borrowed here
 ...
 LL |         _a = 4;
-   |         ^^^^^^ assignment to borrowed `_a` occurs here
+   |         ^^^^^^ `_a` is assigned to here but it was already borrowed
 ...
 LL |     drop(b);
    |          - borrow later used here
index 42a55b7a854ba407b8670ea37dde36b86c61302f..374c5ee3ed27b7a28b733c107dfe69db74920d10 100644 (file)
@@ -13,10 +13,10 @@ error[E0506]: cannot assign to `**y` because it is borrowed
   --> $DIR/borrowck-issue-14498.rs:25:5
    |
 LL |     let p = &y;
-   |             -- borrow of `**y` occurs here
+   |             -- `**y` is borrowed here
 LL |     let q = &***p;
 LL |     **y = 2;
-   |     ^^^^^^^ assignment to borrowed `**y` occurs here
+   |     ^^^^^^^ `**y` is assigned to here but it was already borrowed
 LL |     drop(p);
    |          - borrow later used here
 
@@ -24,10 +24,10 @@ error[E0506]: cannot assign to `**y` because it is borrowed
   --> $DIR/borrowck-issue-14498.rs:35:5
    |
 LL |     let p = &y;
-   |             -- borrow of `**y` occurs here
+   |             -- `**y` is borrowed here
 LL |     let q = &***p;
 LL |     **y = 2;
-   |     ^^^^^^^ assignment to borrowed `**y` occurs here
+   |     ^^^^^^^ `**y` is assigned to here but it was already borrowed
 LL |     drop(p);
    |          - borrow later used here
 
@@ -35,10 +35,10 @@ error[E0506]: cannot assign to `**y` because it is borrowed
   --> $DIR/borrowck-issue-14498.rs:45:5
    |
 LL |     let p = &y;
-   |             -- borrow of `**y` occurs here
+   |             -- `**y` is borrowed here
 LL |     let q = &***p;
 LL |     **y = 2;
-   |     ^^^^^^^ assignment to borrowed `**y` occurs here
+   |     ^^^^^^^ `**y` is assigned to here but it was already borrowed
 LL |     drop(p);
    |          - borrow later used here
 
@@ -46,10 +46,10 @@ error[E0506]: cannot assign to `**y` because it is borrowed
   --> $DIR/borrowck-issue-14498.rs:55:5
    |
 LL |     let p = &y;
-   |             -- borrow of `**y` occurs here
+   |             -- `**y` is borrowed here
 LL |     let q = &***p;
 LL |     **y = 2;
-   |     ^^^^^^^ assignment to borrowed `**y` occurs here
+   |     ^^^^^^^ `**y` is assigned to here but it was already borrowed
 LL |     drop(p);
    |          - borrow later used here
 
@@ -57,10 +57,10 @@ error[E0506]: cannot assign to `**y.a` because it is borrowed
   --> $DIR/borrowck-issue-14498.rs:65:5
    |
 LL |     let p = &y.a;
-   |             ---- borrow of `**y.a` occurs here
+   |             ---- `**y.a` is borrowed here
 LL |     let q = &***p;
 LL |     **y.a = 2;
-   |     ^^^^^^^^^ assignment to borrowed `**y.a` occurs here
+   |     ^^^^^^^^^ `**y.a` is assigned to here but it was already borrowed
 LL |     drop(p);
    |          - borrow later used here
 
@@ -68,10 +68,10 @@ error[E0506]: cannot assign to `**y.a` because it is borrowed
   --> $DIR/borrowck-issue-14498.rs:75:5
    |
 LL |     let p = &y.a;
-   |             ---- borrow of `**y.a` occurs here
+   |             ---- `**y.a` is borrowed here
 LL |     let q = &***p;
 LL |     **y.a = 2;
-   |     ^^^^^^^^^ assignment to borrowed `**y.a` occurs here
+   |     ^^^^^^^^^ `**y.a` is assigned to here but it was already borrowed
 LL |     drop(p);
    |          - borrow later used here
 
@@ -79,10 +79,10 @@ error[E0506]: cannot assign to `**y.a` because it is borrowed
   --> $DIR/borrowck-issue-14498.rs:85:5
    |
 LL |     let p = &y.a;
-   |             ---- borrow of `**y.a` occurs here
+   |             ---- `**y.a` is borrowed here
 LL |     let q = &***p;
 LL |     **y.a = 2;
-   |     ^^^^^^^^^ assignment to borrowed `**y.a` occurs here
+   |     ^^^^^^^^^ `**y.a` is assigned to here but it was already borrowed
 LL |     drop(p);
    |          - borrow later used here
 
@@ -90,10 +90,10 @@ error[E0506]: cannot assign to `**y.a` because it is borrowed
   --> $DIR/borrowck-issue-14498.rs:95:5
    |
 LL |     let p = &y.a;
-   |             ---- borrow of `**y.a` occurs here
+   |             ---- `**y.a` is borrowed here
 LL |     let q = &***p;
 LL |     **y.a = 2;
-   |     ^^^^^^^^^ assignment to borrowed `**y.a` occurs here
+   |     ^^^^^^^^^ `**y.a` is assigned to here but it was already borrowed
 LL |     drop(p);
    |          - borrow later used here
 
index 66f1cd9bd5664a68f97ffdae50283138feacaf31..6cdce7bee88975ccf15b12a800e1cd819fce16e7 100644 (file)
@@ -2,9 +2,9 @@ error[E0506]: cannot assign to `x` because it is borrowed
   --> $DIR/borrowck-lend-flow-match.rs:12:13
    |
 LL |         Some(ref r) => {
-   |              ----- borrow of `x` occurs here
+   |              ----- `x` is borrowed here
 LL |             x = Some(1);
-   |             ^^^^^^^^^^^ assignment to borrowed `x` occurs here
+   |             ^^^^^^^^^^^ `x` is assigned to here but it was already borrowed
 LL |             drop(r);
    |                  - borrow later used here
 
index 3548da35b613926a4acf0ef7ebf0585127f2810b..6eabfff9054c4afab0e17080133c0cfb509a6f21 100644 (file)
@@ -1,6 +1,8 @@
 error[E0505]: cannot move out of `v` because it is borrowed
   --> $DIR/borrowck-loan-blocks-move-cc.rs:14:19
    |
+LL |     let v: Box<_> = Box::new(3);
+   |         - binding `v` declared here
 LL |     let w = &v;
    |             -- borrow of `v` occurs here
 LL |     thread::spawn(move|| {
@@ -15,6 +17,8 @@ LL |     w.use_ref();
 error[E0505]: cannot move out of `v` because it is borrowed
   --> $DIR/borrowck-loan-blocks-move-cc.rs:24:19
    |
+LL |     let v: Box<_> = Box::new(3);
+   |         - binding `v` declared here
 LL |     let w = &v;
    |             -- borrow of `v` occurs here
 LL |     thread::spawn(move|| {
index b5c6b101f765caffdb6000162d4ea6cf76b05a2c..38e06fa018786b829b17be72b093d1b8747bb400 100644 (file)
@@ -1,6 +1,8 @@
 error[E0505]: cannot move out of `v` because it is borrowed
   --> $DIR/borrowck-loan-blocks-move.rs:11:10
    |
+LL |     let v = Box::new(3);
+   |         - binding `v` declared here
 LL |     let w = &v;
    |             -- borrow of `v` occurs here
 LL |     take(v);
index 6994c837dfcbe62eb98ae6b9fc4da1db692ae624..311369a260d76e86ba0939dd8e4e8893ead0590c 100644 (file)
@@ -2,12 +2,12 @@ error[E0506]: cannot assign to `*s` because it is borrowed
   --> $DIR/borrowck-loan-of-static-data-issue-27616.rs:16:5
    |
 LL |     let alias: &'static mut String = s;
-   |                -------------------   - borrow of `*s` occurs here
+   |                -------------------   - `*s` is borrowed here
    |                |
    |                type annotation requires that `*s` is borrowed for `'static`
 ...
 LL |     *s = String::new();
-   |     ^^ assignment to borrowed `*s` occurs here
+   |     ^^ `*s` is assigned to here but it was already borrowed
 
 error: aborting due to previous error
 
index 24cc4933ef1b055efa4cf821bb90816c98ce1e46..f1640d3b7776f56fdff5759249439f30858c0628 100644 (file)
@@ -2,7 +2,7 @@ error[E0503]: cannot use `p` because it was mutably borrowed
   --> $DIR/borrowck-loan-rcvr-overloaded-op.rs:38:5
    |
 LL |     let q = &mut p;
-   |             ------ borrow of `p` occurs here
+   |             ------ `p` is borrowed here
 LL |
 LL |     p + 3;
    |     ^ use of borrowed `p`
index 6ea6951ad966541eec0aeb987da3be4f35dba7ac..0fdb1dabbc50c21a5c5155ae04d3b1867435b2f1 100644 (file)
@@ -1,6 +1,8 @@
 error[E0597]: `z.1` does not live long enough
   --> $DIR/borrowck-local-borrow-with-panic-outlives-fn.rs:3:15
    |
+LL |     let mut z = (0, 0);
+   |         ----- binding `z` declared here
 LL |     *x = Some(&mut z.1);
    |     ----------^^^^^^^^-
    |     |         |
index 39047be9de670e667bcd9517168ee5ad6140d64e..e5c0ec960a4a705b2b6d8994b769b655ea6f26ac 100644 (file)
@@ -2,7 +2,7 @@ error[E0503]: cannot use `foo` because it was mutably borrowed
   --> $DIR/borrowck-match-already-borrowed.rs:9:19
    |
 LL |     let p = &mut foo;
-   |             -------- borrow of `foo` occurs here
+   |             -------- `foo` is borrowed here
 LL |     let _ = match foo {
    |                   ^^^ use of borrowed `foo`
 ...
@@ -13,7 +13,7 @@ error[E0503]: cannot use `foo.0` because it was mutably borrowed
   --> $DIR/borrowck-match-already-borrowed.rs:12:16
    |
 LL |     let p = &mut foo;
-   |             -------- borrow of `foo` occurs here
+   |             -------- `foo` is borrowed here
 ...
 LL |         Foo::A(x) => x
    |                ^ use of borrowed `foo`
@@ -25,7 +25,7 @@ error[E0503]: cannot use `x` because it was mutably borrowed
   --> $DIR/borrowck-match-already-borrowed.rs:22:9
    |
 LL |     let r = &mut x;
-   |             ------ borrow of `x` occurs here
+   |             ------ `x` is borrowed here
 LL |     let _ = match x {
 LL |         x => x + 1,
    |         ^ use of borrowed `x`
@@ -37,7 +37,7 @@ error[E0503]: cannot use `x` because it was mutably borrowed
   --> $DIR/borrowck-match-already-borrowed.rs:23:9
    |
 LL |     let r = &mut x;
-   |             ------ borrow of `x` occurs here
+   |             ------ `x` is borrowed here
 ...
 LL |         y => y + 2,
    |         ^ use of borrowed `x`
index 8ddc48b2a99cdf0711a8f7812e1f1c4f9c2ee49f..6eaa1fa3169321fdfeefcb49a50e2be5b1d010ee 100644 (file)
@@ -10,7 +10,7 @@ LL |         let _h = to_fn_once(move || -> isize { *bar });
    |                             |                  |
    |                             |                  variable moved due to use in closure
    |                             |                  move occurs because `bar` has type `Box<isize>`, which does not implement the `Copy` trait
-   |                             move out of `bar` occurs here
+   |                             `bar` is moved here
 
 error: aborting due to previous error
 
index f833abcc02acf83a4335359c739c0658ec4eda33..bd94f1a4299b808dc519713aca3357fe7b917199 100644 (file)
@@ -1,6 +1,8 @@
 error[E0505]: cannot move out of `*a` because it is borrowed
   --> $DIR/borrowck-move-from-subpath-of-borrowed-path.rs:12:13
    |
+LL |     let a: Box<Box<_>> = Box::new(Box::new(2));
+   |         - binding `a` declared here
 LL |     let b = &a;
    |             -- borrow of `a` occurs here
 LL |
index d5ff0c501c4bd00f0a3e7c96c16f7ab9cce8d651..cdad20c52bfaf2fbb021bea3f6d39618db5bb828 100644 (file)
@@ -1,6 +1,8 @@
 error[E0505]: cannot move out of `t0` because it is borrowed
   --> $DIR/borrowck-move-mut-base-ptr.rs:10:14
    |
+LL | fn foo(t0: &mut isize) {
+   |        -- binding `t0` declared here
 LL |     let p: &isize = &*t0; // Freezes `*t0`
    |                     ---- borrow of `*t0` occurs here
 LL |     let t1 = t0;
index 8c9083fcf135642d2ad1da46bb79bc55fd67ff53..341146bd18fd9496c7c0ca389c829d756ba432cd 100644 (file)
@@ -1,6 +1,8 @@
 error[E0505]: cannot move out of `a.x` because it is borrowed
   --> $DIR/borrowck-move-subcomponent.rs:15:14
    |
+LL |   let a : S = S { x : Box::new(1) };
+   |       - binding `a` declared here
 LL |   let pb = &a;
    |            -- borrow of `a` occurs here
 LL |   let S { x: ax } = a;
index f94cbc30db421d77c381e2f123be1c4b464b9bc5..70abe7b346e1a75aaab94c1cdc960aff27b15787 100644 (file)
@@ -1,6 +1,8 @@
 error[E0505]: cannot move out of `x1` because it is borrowed
   --> $DIR/borrowck-multiple-captures.rs:12:19
    |
+LL |     let x1: Box<_> = Box::new(1);
+   |         -- binding `x1` declared here
 LL |     let p1 = &x1;
    |              --- borrow of `x1` occurs here
 ...
@@ -16,6 +18,8 @@ LL |     borrow(&*p1);
 error[E0505]: cannot move out of `x2` because it is borrowed
   --> $DIR/borrowck-multiple-captures.rs:12:19
    |
+LL |     let x2: Box<_> = Box::new(2);
+   |         -- binding `x2` declared here
 LL |     let p2 = &x2;
    |              --- borrow of `x2` occurs here
 LL |     thread::spawn(move|| {
@@ -77,6 +81,8 @@ LL |         drop(x);
 error[E0505]: cannot move out of `x` because it is borrowed
   --> $DIR/borrowck-multiple-captures.rs:38:19
    |
+LL |     let x: Box<_> = Box::new(1);
+   |         - binding `x` declared here
 LL |     let p = &x;
    |             -- borrow of `x` occurs here
 LL |     thread::spawn(move|| {
index 5d52e49191831a143109967ba8010c5ae5103d89..7f42becd21c2a48195af9fc96865de4e77cd1ff9 100644 (file)
@@ -2,9 +2,9 @@ error[E0506]: cannot assign to `v` because it is borrowed
   --> $DIR/borrowck-overloaded-index-and-overloaded-deref.rs:31:5
    |
 LL |     let i = &v[0].f;
-   |              - borrow of `v` occurs here
+   |              - `v` is borrowed here
 LL |     v = MyVec { x: MyPtr { x: Foo { f: 23 } } };
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ assignment to borrowed `v` occurs here
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `v` is assigned to here but it was already borrowed
 LL |
 LL |     read(*i);
    |          -- borrow later used here
index 087f2ac799eebc3eff5668846b48e09d53af8b74..fb7af50bcb5650c7ab7c4659cc401c26ab590333 100644 (file)
@@ -42,9 +42,9 @@ error[E0506]: cannot assign to `f.foo` because it is borrowed
   --> $DIR/borrowck-overloaded-index-autoderef.rs:71:5
    |
 LL |     let p = &f.foo[&s];
-   |              ----- borrow of `f.foo` occurs here
+   |              ----- `f.foo` is borrowed here
 LL |     f.foo = g;
-   |     ^^^^^^^^^ assignment to borrowed `f.foo` occurs here
+   |     ^^^^^^^^^ `f.foo` is assigned to here but it was already borrowed
 LL |     p.use_ref();
    |     ----------- borrow later used here
 
@@ -52,9 +52,9 @@ error[E0506]: cannot assign to `*f` because it is borrowed
   --> $DIR/borrowck-overloaded-index-autoderef.rs:77:5
    |
 LL |     let p = &f.foo[&s];
-   |              ----- borrow of `*f` occurs here
+   |              ----- `*f` is borrowed here
 LL |     *f = g;
-   |     ^^^^^^ assignment to borrowed `*f` occurs here
+   |     ^^^^^^ `*f` is assigned to here but it was already borrowed
 LL |     p.use_ref();
    |     ----------- borrow later used here
 
@@ -62,9 +62,9 @@ error[E0506]: cannot assign to `f.foo` because it is borrowed
   --> $DIR/borrowck-overloaded-index-autoderef.rs:83:5
    |
 LL |     let p = &mut f.foo[&s];
-   |                  ----- borrow of `f.foo` occurs here
+   |                  ----- `f.foo` is borrowed here
 LL |     f.foo = g;
-   |     ^^^^^^^^^ assignment to borrowed `f.foo` occurs here
+   |     ^^^^^^^^^ `f.foo` is assigned to here but it was already borrowed
 LL |     p.use_mut();
    |     ----------- borrow later used here
 
@@ -72,9 +72,9 @@ error[E0506]: cannot assign to `*f` because it is borrowed
   --> $DIR/borrowck-overloaded-index-autoderef.rs:89:5
    |
 LL |     let p = &mut f.foo[&s];
-   |                  ----- borrow of `*f` occurs here
+   |                  ----- `*f` is borrowed here
 LL |     *f = g;
-   |     ^^^^^^ assignment to borrowed `*f` occurs here
+   |     ^^^^^^ `*f` is assigned to here but it was already borrowed
 LL |     p.use_mut();
    |     ----------- borrow later used here
 
index fb0e274c2919ab2958b9110b31ed8337cf3d617d..7f8cc74a7157a695bfa7b45fe47776384e97b5ec 100644 (file)
@@ -1,6 +1,8 @@
 error[E0505]: cannot move out of `s` because it is borrowed
   --> $DIR/borrowck-overloaded-index-move-index.rs:50:22
    |
+LL |     let mut s = "hello".to_string();
+   |         ----- binding `s` declared here
 LL |     let rs = &mut s;
    |              ------ borrow of `s` occurs here
 LL |
@@ -13,6 +15,8 @@ LL |     use_mut(rs);
 error[E0505]: cannot move out of `s` because it is borrowed
   --> $DIR/borrowck-overloaded-index-move-index.rs:53:7
    |
+LL |     let mut s = "hello".to_string();
+   |         ----- binding `s` declared here
 LL |     let rs = &mut s;
    |              ------ borrow of `s` occurs here
 ...
index 9e65ccf5a1913ea9b8bfedb6efec7198c6b491e2..b86a8693881a96aca5e8b5db0f40c0a68b3c60e5 100644 (file)
@@ -2,10 +2,10 @@ error[E0506]: cannot assign to `x` because it is borrowed
   --> $DIR/borrowck-pat-reassign-binding.rs:10:11
    |
 LL |       Some(ref i) => {
-   |            ----- borrow of `x` occurs here
+   |            ----- `x` is borrowed here
 LL |           // But on this branch, `i` is an outstanding borrow
 LL |           x = Some(*i+1);
-   |           ^^^^^^^^^^^^^^ assignment to borrowed `x` occurs here
+   |           ^^^^^^^^^^^^^^ `x` is assigned to here but it was already borrowed
 LL |           drop(i);
    |                - borrow later used here
 
index aab225ed4a429873dd4f002d96607f7e4f0b4aa9..f3b962059f5b467236970383083511b4f7bb9e12 100644 (file)
@@ -1,6 +1,8 @@
 error[E0505]: cannot move out of `x` because it is borrowed
   --> $DIR/borrowck-unary-move.rs:3:10
    |
+LL | fn foo(x: Box<isize>) -> isize {
+   |        - binding `x` declared here
 LL |     let y = &*x;
    |             --- borrow of `*x` occurs here
 LL |     free(x);
index 4bd7d54cffedacef1094d6e49cac88aeb5763c9b..a87a14e7cabd8fca08a63458e855f4772c952dd4 100644 (file)
@@ -2,7 +2,7 @@ error[E0503]: cannot use `u.c` because it was mutably borrowed
   --> $DIR/borrowck-union-borrow-nested.rs:24:21
    |
 LL |             let ra = &mut u.s.a;
-   |                      ---------- borrow of `u.s.a` occurs here
+   |                      ---------- `u.s.a` is borrowed here
 LL |             let b = u.c;
    |                     ^^^ use of borrowed `u.s.a`
 LL |             ra.use_mut();
index 090c7b6b51a31cf27390e59e9cbdf0ee4a6555d6..11a28f6744b701da2a32a8f80ed862c882133859 100644 (file)
@@ -12,9 +12,9 @@ error[E0506]: cannot assign to `u.a` because it is borrowed
   --> $DIR/borrowck-union-borrow.rs:28:13
    |
 LL |             let ra = &u.a;
-   |                      ---- borrow of `u.a` occurs here
+   |                      ---- `u.a` is borrowed here
 LL |             u.a = 1;
-   |             ^^^^^^^ assignment to borrowed `u.a` occurs here
+   |             ^^^^^^^ `u.a` is assigned to here but it was already borrowed
 LL |             drop(ra);
    |                  -- borrow later used here
 
@@ -34,9 +34,9 @@ error[E0506]: cannot assign to `u.b` because it is borrowed
   --> $DIR/borrowck-union-borrow.rs:49:13
    |
 LL |             let ra = &u.a;
-   |                      ---- borrow of `u.b` occurs here
+   |                      ---- `u.b` is borrowed here
 LL |             u.b = 1;
-   |             ^^^^^^^ assignment to borrowed `u.b` occurs here
+   |             ^^^^^^^ `u.b` is assigned to here but it was already borrowed
 LL |             drop(ra);
    |                  -- borrow later used here
 
@@ -54,7 +54,7 @@ error[E0503]: cannot use `u.a` because it was mutably borrowed
   --> $DIR/borrowck-union-borrow.rs:60:21
    |
 LL |             let ra = &mut u.a;
-   |                      -------- borrow of `u.a` occurs here
+   |                      -------- `u.a` is borrowed here
 LL |             let a = u.a;
    |                     ^^^ use of borrowed `u.a`
 LL |             drop(ra);
@@ -74,9 +74,9 @@ error[E0506]: cannot assign to `u.a` because it is borrowed
   --> $DIR/borrowck-union-borrow.rs:70:13
    |
 LL |             let rma = &mut u.a;
-   |                       -------- borrow of `u.a` occurs here
+   |                       -------- `u.a` is borrowed here
 LL |             u.a = 1;
-   |             ^^^^^^^ assignment to borrowed `u.a` occurs here
+   |             ^^^^^^^ `u.a` is assigned to here but it was already borrowed
 LL |             drop(rma);
    |                  --- borrow later used here
 
@@ -96,7 +96,7 @@ error[E0503]: cannot use `u.b` because it was mutably borrowed
   --> $DIR/borrowck-union-borrow.rs:81:21
    |
 LL |             let ra = &mut u.a;
-   |                      -------- borrow of `u.a` occurs here
+   |                      -------- `u.a` is borrowed here
 LL |             let b = u.b;
    |                     ^^^ use of borrowed `u.a`
 LL |
@@ -119,9 +119,9 @@ error[E0506]: cannot assign to `u.b` because it is borrowed
   --> $DIR/borrowck-union-borrow.rs:92:13
    |
 LL |             let rma = &mut u.a;
-   |                       -------- borrow of `u.b` occurs here
+   |                       -------- `u.b` is borrowed here
 LL |             u.b = 1;
-   |             ^^^^^^^ assignment to borrowed `u.b` occurs here
+   |             ^^^^^^^ `u.b` is assigned to here but it was already borrowed
 LL |             drop(rma);
    |                  --- borrow later used here
 
index 91d69c51e8180d6f931b44478974ee286397657e..4d300ae3c527b3c8610f6098c29298c7d624f444 100644 (file)
@@ -2,7 +2,7 @@ error[E0503]: cannot use `x` because it was mutably borrowed
   --> $DIR/borrowck-use-mut-borrow.rs:11:10
    |
 LL |     let p = &mut x;
-   |             ------ borrow of `x` occurs here
+   |             ------ `x` is borrowed here
 LL |     drop(x);
    |          ^ use of borrowed `x`
 LL |     *p = 2;
@@ -12,7 +12,7 @@ error[E0503]: cannot use `x` because it was mutably borrowed
   --> $DIR/borrowck-use-mut-borrow.rs:18:10
    |
 LL |     let p = &mut x.a;
-   |             -------- borrow of `x.a` occurs here
+   |             -------- `x.a` is borrowed here
 LL |     drop(x);
    |          ^ use of borrowed `x.a`
 LL |     *p = 3;
@@ -22,7 +22,7 @@ error[E0503]: cannot use `x.a` because it was mutably borrowed
   --> $DIR/borrowck-use-mut-borrow.rs:25:10
    |
 LL |     let p = &mut x;
-   |             ------ borrow of `x` occurs here
+   |             ------ `x` is borrowed here
 LL |     drop(x.a);
    |          ^^^ use of borrowed `x`
 LL |     p.a = 3;
@@ -32,7 +32,7 @@ error[E0503]: cannot use `x.a` because it was mutably borrowed
   --> $DIR/borrowck-use-mut-borrow.rs:32:10
    |
 LL |     let p = &mut x.a;
-   |             -------- borrow of `x.a` occurs here
+   |             -------- `x.a` is borrowed here
 LL |     drop(x.a);
    |          ^^^ use of borrowed `x.a`
 LL |     *p = 3;
@@ -42,7 +42,7 @@ error[E0503]: cannot use `x.a` because it was mutably borrowed
   --> $DIR/borrowck-use-mut-borrow.rs:39:13
    |
 LL |     let p = &mut x;
-   |             ------ borrow of `x` occurs here
+   |             ------ `x` is borrowed here
 LL |     let y = A { b: 3, .. x };
    |             ^^^^^^^^^^^^^^^^ use of borrowed `x`
 LL |     drop(y);
@@ -53,7 +53,7 @@ error[E0503]: cannot use `x.a` because it was mutably borrowed
   --> $DIR/borrowck-use-mut-borrow.rs:47:13
    |
 LL |     let p = &mut x.a;
-   |             -------- borrow of `x.a` occurs here
+   |             -------- `x.a` is borrowed here
 LL |     let y = A { b: 3, .. x };
    |             ^^^^^^^^^^^^^^^^ use of borrowed `x.a`
 LL |     drop(y);
@@ -64,7 +64,7 @@ error[E0503]: cannot use `*x` because it was mutably borrowed
   --> $DIR/borrowck-use-mut-borrow.rs:55:10
    |
 LL |     let p = &mut x;
-   |             ------ borrow of `x` occurs here
+   |             ------ `x` is borrowed here
 LL |     drop(*x);
    |          ^^ use of borrowed `x`
 LL |     **p = 2;
@@ -74,7 +74,7 @@ error[E0503]: cannot use `*x.b` because it was mutably borrowed
   --> $DIR/borrowck-use-mut-borrow.rs:62:10
    |
 LL |     let p = &mut x;
-   |             ------ borrow of `x` occurs here
+   |             ------ `x` is borrowed here
 LL |     drop(*x.b);
    |          ^^^^ use of borrowed `x`
 LL |     p.a = 3;
@@ -84,7 +84,7 @@ error[E0503]: cannot use `*x.b` because it was mutably borrowed
   --> $DIR/borrowck-use-mut-borrow.rs:69:10
    |
 LL |     let p = &mut x.b;
-   |             -------- borrow of `x.b` occurs here
+   |             -------- `x.b` is borrowed here
 LL |     drop(*x.b);
    |          ^^^^ use of borrowed `x.b`
 LL |     **p = 3;
index 0ac7df944d78114ad1de4c57ea5eaac14fa2a8d7..494d8c351a152930852687740887b1342dd79cd8 100644 (file)
@@ -2,10 +2,10 @@ error[E0506]: cannot assign to `a[_]` because it is borrowed
   --> $DIR/borrowck-vec-pattern-move-tail.rs:8:5
    |
 LL |         [1, 2, ref tail @ ..] => tail,
-   |                -------- borrow of `a[_]` occurs here
+   |                -------- `a[_]` is borrowed here
 ...
 LL |     a[2] = 0;
-   |     ^^^^^^^^ assignment to borrowed `a[_]` occurs here
+   |     ^^^^^^^^ `a[_]` is assigned to here but it was already borrowed
 LL |     println!("t[0]: {}", t[0]);
    |                          ---- borrow later used here
 
index 0e9284a2cadd26cf48564328da88ebe070829077..1bda7a4971375491003540a23cfc68c4a02887f5 100644 (file)
@@ -5,9 +5,9 @@ fn a() {
     let mut vec = [Box::new(1), Box::new(2), Box::new(3)];
     match vec {
         [box ref _a, _, _] => {
-        //~^ NOTE borrow of `vec[_]` occurs here
+        //~^ NOTE `vec[_]` is borrowed here
             vec[0] = Box::new(4); //~ ERROR cannot assign
-            //~^ NOTE assignment to borrowed `vec[_]` occurs here
+            //~^ NOTE `vec[_]` is assigned to here
             _a.use_ref();
             //~^ NOTE borrow later used here
         }
@@ -19,9 +19,9 @@ fn b() {
     let vec: &mut [Box<isize>] = &mut vec;
     match vec {
         &mut [ref _b @ ..] => {
-        //~^ borrow of `vec[_]` occurs here
+        //~^ `vec[_]` is borrowed here
             vec[0] = Box::new(4); //~ ERROR cannot assign
-            //~^ NOTE assignment to borrowed `vec[_]` occurs here
+            //~^ NOTE `vec[_]` is assigned to here
             _b.use_ref();
             //~^ NOTE borrow later used here
         }
index 0dc5e64e4ff3022ee92075d07b49bd3c2134729e..70b9e4f4433b34e8ae6926e2fd507c658bf92c15 100644 (file)
@@ -2,10 +2,10 @@ error[E0506]: cannot assign to `vec[_]` because it is borrowed
   --> $DIR/borrowck-vec-pattern-nesting.rs:9:13
    |
 LL |         [box ref _a, _, _] => {
-   |              ------ borrow of `vec[_]` occurs here
+   |              ------ `vec[_]` is borrowed here
 LL |
 LL |             vec[0] = Box::new(4);
-   |             ^^^^^^ assignment to borrowed `vec[_]` occurs here
+   |             ^^^^^^ `vec[_]` is assigned to here but it was already borrowed
 LL |
 LL |             _a.use_ref();
    |             ------------ borrow later used here
@@ -14,10 +14,10 @@ error[E0506]: cannot assign to `vec[_]` because it is borrowed
   --> $DIR/borrowck-vec-pattern-nesting.rs:23:13
    |
 LL |         &mut [ref _b @ ..] => {
-   |               ------ borrow of `vec[_]` occurs here
+   |               ------ `vec[_]` is borrowed here
 LL |
 LL |             vec[0] = Box::new(4);
-   |             ^^^^^^ assignment to borrowed `vec[_]` occurs here
+   |             ^^^^^^ `vec[_]` is assigned to here but it was already borrowed
 LL |
 LL |             _b.use_ref();
    |             ------------ borrow later used here
index da3412f112d7a9e4f064966d13fca062920bf222..27dab53e48fd5c93fad79b6af16e57d474b2b7a2 100644 (file)
@@ -5,7 +5,7 @@ LL |         $this.width.unwrap()
    |         ^^^^^^^^^^^ use of borrowed `*self`
 ...
 LL |         let r = &mut *self;
-   |                 ---------- borrow of `*self` occurs here
+   |                 ---------- `*self` is borrowed here
 LL |         r.get_size(width!(self))
    |           -------- ------------ in this macro invocation
    |           |
index 4abb6fb2c71868674dbf2266cd1c3afae61c9c71..3f7715645e60c28f56c0a17f1003daef69310409 100644 (file)
@@ -2,10 +2,10 @@ error[E0506]: cannot assign to `x` because it is borrowed
   --> $DIR/issue-52713-bug.rs:12:5
    |
 LL |     let y = &x;
-   |             -- borrow of `x` occurs here
+   |             -- `x` is borrowed here
 ...
 LL |     x += 1;
-   |     ^^^^^^ assignment to borrowed `x` occurs here
+   |     ^^^^^^ `x` is assigned to here but it was already borrowed
 LL |     println!("{}", y);
    |                    - borrow later used here
 
index 57803247ba8d05fa0ee37e700456d830d7558b81..0870b4237690e2b8040ee74cbc132292023c4079 100644 (file)
@@ -4,10 +4,10 @@ error[E0506]: cannot assign to `greeting` because it is borrowed
 LL |     let res = (|| (|| &greeting)())();
    |                --      -------- borrow occurs due to use in closure
    |                |
-   |                borrow of `greeting` occurs here
+   |                `greeting` is borrowed here
 LL |
 LL |     greeting = "DEALLOCATED".to_string();
-   |     ^^^^^^^^ assignment to borrowed `greeting` occurs here
+   |     ^^^^^^^^ `greeting` is assigned to here but it was already borrowed
 ...
 LL |     println!("thread result: {:?}", res);
    |                                     --- borrow later used here
index d79394834dcad615cab6f1d3dfc8a0c0f63b8392..0d803b0427ace43bfbf752f704fa7bc85f5bdc59 100644 (file)
@@ -2,9 +2,9 @@ error[E0506]: cannot assign to `self.container_field` because it is borrowed
   --> $DIR/issue-81365-1.rs:21:9
    |
 LL |         let first = &self.target_field;
-   |                      ---- borrow of `self.container_field` occurs here
+   |                      ---- `self.container_field` is borrowed here
 LL |         self.container_field = true;
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^ assignment to borrowed `self.container_field` occurs here
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^ `self.container_field` is assigned to here but it was already borrowed
 LL |         first;
    |         ----- borrow later used here
    |
index 27123ef2be1ef91355c9f789a0aad0fd75cc8f08..d0986e9f922e656ca3d21f32db01b9be30af287d 100644 (file)
@@ -2,9 +2,9 @@ error[E0506]: cannot assign to `self.container_field` because it is borrowed
   --> $DIR/issue-81365-10.rs:21:9
    |
 LL |         let first = &self.deref().target_field;
-   |                      ------------ borrow of `self.container_field` occurs here
+   |                      ------------ `self.container_field` is borrowed here
 LL |         self.container_field = true;
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^ assignment to borrowed `self.container_field` occurs here
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^ `self.container_field` is assigned to here but it was already borrowed
 LL |         first;
    |         ----- borrow later used here
 
index 0770c136632db1f9603c2d6ef0e68ab8c6331a5e..5f7e86f11dcd1daeb15ba92f150e9458b27bcbe6 100644 (file)
@@ -2,9 +2,9 @@ error[E0506]: cannot assign to `self.container_field` because it is borrowed
   --> $DIR/issue-81365-11.rs:27:9
    |
 LL |         let first = &mut self.target_field;
-   |                          ---- borrow of `self.container_field` occurs here
+   |                          ---- `self.container_field` is borrowed here
 LL |         self.container_field = true;
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^ assignment to borrowed `self.container_field` occurs here
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^ `self.container_field` is assigned to here but it was already borrowed
 LL |         first;
    |         ----- borrow later used here
 
index 764eaaa7cc7b4cb253846e71101af7b2e13c60f8..d9aeaf15f2002679a8867f852e2035387f84b600 100644 (file)
@@ -2,9 +2,9 @@ error[E0506]: cannot assign to `self.container.container_field` because it is bo
   --> $DIR/issue-81365-2.rs:25:9
    |
 LL |         let first = &self.container.target_field;
-   |                      -------------- borrow of `self.container.container_field` occurs here
+   |                      -------------- `self.container.container_field` is borrowed here
 LL |         self.container.container_field = true;
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ assignment to borrowed `self.container.container_field` occurs here
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `self.container.container_field` is assigned to here but it was already borrowed
 LL |         first;
    |         ----- borrow later used here
    |
index 9447174fd21ea2e7dbb1568f38ea9f1f688e110a..0c0d1994baff2a3359b782aeb8f24eb79098d536 100644 (file)
@@ -2,9 +2,9 @@ error[E0506]: cannot assign to `self.container.container_field` because it is bo
   --> $DIR/issue-81365-3.rs:32:9
    |
 LL |         let first = &self.target_field;
-   |                      ---- borrow of `self.container.container_field` occurs here
+   |                      ---- `self.container.container_field` is borrowed here
 LL |         self.container.container_field = true;
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ assignment to borrowed `self.container.container_field` occurs here
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `self.container.container_field` is assigned to here but it was already borrowed
 LL |         first;
    |         ----- borrow later used here
    |
index 0ab3fa92706b059b525a522237778c9f741ce922..98093daa94520ca577eff8b80250fe28d4cb8307 100644 (file)
@@ -2,9 +2,9 @@ error[E0506]: cannot assign to `self.outer_field` because it is borrowed
   --> $DIR/issue-81365-4.rs:33:9
    |
 LL |         let first = &self.target_field;
-   |                      ---- borrow of `self.outer_field` occurs here
+   |                      ---- `self.outer_field` is borrowed here
 LL |         self.outer_field = true;
-   |         ^^^^^^^^^^^^^^^^^^^^^^^ assignment to borrowed `self.outer_field` occurs here
+   |         ^^^^^^^^^^^^^^^^^^^^^^^ `self.outer_field` is assigned to here but it was already borrowed
 LL |         first;
    |         ----- borrow later used here
    |
index 20ff229ffe7dd3ed1c6e9aedd1980c0eefe8dd26..c00e48288ba075985af16bcef0309e9117362770 100644 (file)
@@ -2,9 +2,9 @@ error[E0506]: cannot assign to `self.container_field` because it is borrowed
   --> $DIR/issue-81365-5.rs:28:9
    |
 LL |         let first = self.get();
-   |                     ---------- borrow of `self.container_field` occurs here
+   |                     ---------- `self.container_field` is borrowed here
 LL |         self.container_field = true;
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^ assignment to borrowed `self.container_field` occurs here
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^ `self.container_field` is assigned to here but it was already borrowed
 LL |         first;
    |         ----- borrow later used here
    |
index 575aed73b4663107b2a0232e864cd429e741c0a9..e61dc95ecc8fad2526d5145e04336c0170a9a33c 100644 (file)
@@ -2,9 +2,9 @@ error[E0506]: cannot assign to `self.container_field` because it is borrowed
   --> $DIR/issue-81365-6.rs:18:9
    |
 LL |         let first = &self[0];
-   |                      ---- borrow of `self.container_field` occurs here
+   |                      ---- `self.container_field` is borrowed here
 LL |         self.container_field = true;
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^ assignment to borrowed `self.container_field` occurs here
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^ `self.container_field` is assigned to here but it was already borrowed
 LL |         first;
    |         ----- borrow later used here
    |
index 52d2d9e75a9515c317fa7cc8d7bb550d090427ea..0565127e3875be859af07a4c8697ce88fdb76062 100644 (file)
@@ -2,9 +2,9 @@ error[E0506]: cannot assign to `c.container_field` because it is borrowed
   --> $DIR/issue-81365-7.rs:20:5
    |
 LL |     let first = &c.target_field;
-   |                  - borrow of `c.container_field` occurs here
+   |                  - `c.container_field` is borrowed here
 LL |     c.container_field = true;
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^ assignment to borrowed `c.container_field` occurs here
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^ `c.container_field` is assigned to here but it was already borrowed
 LL |     first;
    |     ----- borrow later used here
    |
index fd83e10a295dc10f47913308cacdc8c58c94c28d..0ca732ff2ae434b6709cf120c39cdbc23a4f838b 100644 (file)
@@ -2,9 +2,9 @@ error[E0506]: cannot assign to `self.container_field` because it is borrowed
   --> $DIR/issue-81365-8.rs:21:9
    |
 LL |         let first = &(*self).target_field;
-   |                      ------- borrow of `self.container_field` occurs here
+   |                      ------- `self.container_field` is borrowed here
 LL |         self.container_field = true;
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^ assignment to borrowed `self.container_field` occurs here
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^ `self.container_field` is assigned to here but it was already borrowed
 LL |         first;
    |         ----- borrow later used here
    |
index c7d48214fd4a81bb9abeaf08aa9b8f6b983a8074..4d305268a0b33d5841baecb7e28ebe8f67a35149 100644 (file)
@@ -2,9 +2,9 @@ error[E0506]: cannot assign to `self.container_field` because it is borrowed
   --> $DIR/issue-81365-9.rs:21:9
    |
 LL |         let first = &Deref::deref(self).target_field;
-   |                                   ---- borrow of `self.container_field` occurs here
+   |                                   ---- `self.container_field` is borrowed here
 LL |         self.container_field = true;
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^ assignment to borrowed `self.container_field` occurs here
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^ `self.container_field` is assigned to here but it was already borrowed
 LL |         first;
    |         ----- borrow later used here
 
index a57ceb847394563448a27e5c98711b60c6814ef9..1356c80493cdb8b441d368913d1b7c3fe6b790a9 100644 (file)
@@ -2,7 +2,7 @@ error[E0503]: cannot use `i` because it was mutably borrowed
   --> $DIR/two-phase-allow-access-during-reservation.rs:26:19
    |
 LL |     /*1*/ let p = &mut i; // (reservation of `i` starts here)
-   |                   ------ borrow of `i` occurs here
+   |                   ------ `i` is borrowed here
 LL |
 LL |     /*2*/ let j = i;      // OK: `i` is only reserved here
    |                   ^ use of borrowed `i`
@@ -14,7 +14,7 @@ error[E0503]: cannot use `i` because it was mutably borrowed
   --> $DIR/two-phase-allow-access-during-reservation.rs:31:19
    |
 LL |     /*1*/ let p = &mut i; // (reservation of `i` starts here)
-   |                   ------ borrow of `i` occurs here
+   |                   ------ `i` is borrowed here
 ...
 LL |     /*4*/ let k = i;
    |                   ^ use of borrowed `i`
index 5a240d90011e4ea64d9232947dd260f1a647ad6b..e75094d4f1309eba7f17640e89c340de14195a6f 100644 (file)
@@ -2,7 +2,7 @@ error[E0503]: cannot use `self.cx` because it was mutably borrowed
   --> $DIR/two-phase-surprise-no-conflict.rs:21:23
    |
 LL |         let _mut_borrow = &mut *self;
-   |                           ---------- borrow of `*self` occurs here
+   |                           ---------- `*self` is borrowed here
 LL |         let _access = self.cx;
    |                       ^^^^^^^ use of borrowed `*self`
 LL |
index e8a6ad0995a0fa555fdd21ac4cfb519d89d9a4f0..5140b58934a5cf34467d7f02ece576f315ba09e2 100644 (file)
@@ -1,6 +1,8 @@
 error[E0505]: cannot move out of `alloc` because it is borrowed
   --> $DIR/leak-alloc.rs:26:10
    |
+LL |     let alloc = Alloc {};
+   |         ----- binding `alloc` declared here
 LL |     let boxed = Box::new_in(10, alloc.by_ref());
    |                                 -------------- borrow of `alloc` occurs here
 LL |     let theref = Box::leak(boxed);
index e953e7ae82bb8443f17b230b9d465d2d5315a633..d405e465aaeea2e27f87ed94748748a127b5646d 100644 (file)
@@ -1,6 +1,8 @@
 error[E0505]: cannot move out of `s` because it is borrowed
   --> $DIR/btreemap_dropck.rs:15:10
    |
+LL |     let s = String::from("Hello World!");
+   |         - binding `s` declared here
 LL |     let _map = BTreeMap::from_iter([((), PrintOnDrop(&s))]);
    |                                                      -- borrow of `s` occurs here
 LL |     drop(s);
index 6f8e53298ace2ccf88385f2b5b7f181ab6ac5da7..c9d90d73dea318d661ddee493307401b6d07de8a 100644 (file)
@@ -107,7 +107,9 @@ error[E0597]: `ap1` does not live long enough
   --> $DIR/variadic-ffi-4.rs:28:11
    |
 LL | pub unsafe extern "C" fn no_escape4(_: usize, mut ap0: &mut VaListImpl, mut ap1: ...) {
-   |                                                        - let's call the lifetime of this reference `'3`
+   |                                                        -                ------- binding `ap1` declared here
+   |                                                        |
+   |                                                        let's call the lifetime of this reference `'3`
 LL |     ap0 = &mut ap1;
    |     ------^^^^^^^^
    |     |     |
index 4f41060dc9842c8a304a2ea1bf2d81cec1b61fdb..9e5200ef34b54204a4b5fa37748cea128a01850a 100644 (file)
@@ -2,7 +2,7 @@ error[E0503]: cannot use `arr` because it was mutably borrowed
   --> $DIR/arrays.rs:14:5
    |
 LL |     let mut c = || {
-   |                 -- borrow of `arr` occurs here
+   |                 -- `arr` is borrowed here
 LL |         arr[0] += 10;
    |         --- borrow occurs due to use of `arr` in closure
 ...
@@ -16,7 +16,7 @@ error[E0503]: cannot use `arr[_]` because it was mutably borrowed
   --> $DIR/arrays.rs:14:5
    |
 LL |     let mut c = || {
-   |                 -- borrow of `arr` occurs here
+   |                 -- `arr` is borrowed here
 LL |         arr[0] += 10;
    |         --- borrow occurs due to use of `arr` in closure
 ...
@@ -30,12 +30,12 @@ error[E0506]: cannot assign to `arr[_]` because it is borrowed
   --> $DIR/arrays.rs:29:5
    |
 LL |     let c = || {
-   |             -- borrow of `arr[_]` occurs here
+   |             -- `arr[_]` is borrowed here
 LL |         println!("{:#?}", &arr[3..4]);
    |                            --- borrow occurs due to use in closure
 ...
 LL |     arr[1] += 10;
-   |     ^^^^^^^^^^^^ assignment to borrowed `arr[_]` occurs here
+   |     ^^^^^^^^^^^^ `arr[_]` is assigned to here but it was already borrowed
 LL |
 LL |     c();
    |     - borrow later used here
@@ -44,12 +44,12 @@ error[E0506]: cannot assign to `arr[_]` because it is borrowed
   --> $DIR/arrays.rs:43:5
    |
 LL |     let c = || {
-   |             -- borrow of `arr[_]` occurs here
+   |             -- `arr[_]` is borrowed here
 LL |         println!("{}", arr[3]);
    |                        --- borrow occurs due to use in closure
 ...
 LL |     arr[1] += 10;
-   |     ^^^^^^^^^^^^ assignment to borrowed `arr[_]` occurs here
+   |     ^^^^^^^^^^^^ `arr[_]` is assigned to here but it was already borrowed
 LL |
 LL |     c();
    |     - borrow later used here
@@ -58,7 +58,7 @@ error[E0503]: cannot use `arr` because it was mutably borrowed
   --> $DIR/arrays.rs:57:20
    |
 LL |     let mut c = || {
-   |                 -- borrow of `arr` occurs here
+   |                 -- `arr` is borrowed here
 LL |         arr[1] += 10;
    |         --- borrow occurs due to use of `arr` in closure
 ...
index f8b178752351acbb2bc54d2cdd4953e04c2c40fc..2e3259e64059615f8eedb4a9c988f0fbcdfa6922 100644 (file)
@@ -2,12 +2,12 @@ error[E0506]: cannot assign to `e.0.0.m.x` because it is borrowed
   --> $DIR/box.rs:21:5
    |
 LL |     let mut c = || {
-   |                 -- borrow of `e.0.0.m.x` occurs here
+   |                 -- `e.0.0.m.x` is borrowed here
 LL |         e.0.0.m.x = format!("not-x");
    |         --------- borrow occurs due to use in closure
 ...
 LL |     e.0.0.m.x = format!("not-x");
-   |     ^^^^^^^^^ assignment to borrowed `e.0.0.m.x` occurs here
+   |     ^^^^^^^^^ `e.0.0.m.x` is assigned to here but it was already borrowed
 LL |
 LL |     c();
    |     - borrow later used here
@@ -32,12 +32,12 @@ error[E0506]: cannot assign to `e.0.0.m.x` because it is borrowed
   --> $DIR/box.rs:55:5
    |
 LL |     let c = || {
-   |             -- borrow of `e.0.0.m.x` occurs here
+   |             -- `e.0.0.m.x` is borrowed here
 LL |         println!("{}", e.0.0.m.x);
    |                        --------- borrow occurs due to use in closure
 ...
 LL |     e.0.0.m.x = format!("not-x");
-   |     ^^^^^^^^^ assignment to borrowed `e.0.0.m.x` occurs here
+   |     ^^^^^^^^^ `e.0.0.m.x` is assigned to here but it was already borrowed
 LL |
 LL |     c();
    |     - borrow later used here
index 46b54846e32ebdc1960692c7ca0204bec7ac94f6..695337ea82cf9fadc2f22ae1fe2c99069c124646 100644 (file)
@@ -11,7 +11,7 @@ union A {
 fn main() {
     let mut a = A { y: 1 };
     let mut c = || {
-    //~^ borrow of `a.y` occurs here
+    //~^ `a.y` is borrowed here
         let _ = unsafe { &a.y };
         let _ = &mut a;
         //~^ borrow occurs due to use in closure
@@ -19,7 +19,7 @@ fn main() {
     };
     a.y = 1;
     //~^ cannot assign to `a.y` because it is borrowed [E0506]
-    //~| assignment to borrowed `a.y` occurs here
+    //~| `a.y` is assigned to here
     c();
     //~^ borrow later used here
 }
index 7c34e2336c867487444c10479c9d8b43e81cfad8..17834e6123628a1f47df5152ebd8a7bc71b1831b 100644 (file)
@@ -2,13 +2,13 @@ error[E0506]: cannot assign to `a.y` because it is borrowed
   --> $DIR/union.rs:20:5
    |
 LL |     let mut c = || {
-   |                 -- borrow of `a.y` occurs here
+   |                 -- `a.y` is borrowed here
 ...
 LL |         let _ = &mut a;
    |                      - borrow occurs due to use in closure
 ...
 LL |     a.y = 1;
-   |     ^^^^^^^ assignment to borrowed `a.y` occurs here
+   |     ^^^^^^^ `a.y` is assigned to here but it was already borrowed
 ...
 LL |     c();
    |     - borrow later used here
index d067c3b3a18056c1f3e5bb5c79b02da297ae17c5..d412b8b08b79a8a865d784560db0945c1b1c9d0f 100644 (file)
@@ -13,10 +13,10 @@ error[E0506]: cannot assign to `**x` because it is borrowed
   --> $DIR/coerce-overloaded-autoderef-fail.rs:17:5
    |
 LL |     let y = borrow(x);
-   |                    - borrow of `**x` occurs here
+   |                    - `**x` is borrowed here
 LL |     let z = borrow(x);
 LL |     **x += 1;
-   |     ^^^^^^^^ assignment to borrowed `**x` occurs here
+   |     ^^^^^^^^ `**x` is assigned to here but it was already borrowed
 LL |
 LL |     drop((y, z));
    |           - borrow later used here
index 975a235a6495b6f3a587bd2306e3086c5f7fb901..6e0349a4773cdd8ee77cd9d390ce0cfa8d731f83 100644 (file)
@@ -4,6 +4,7 @@ error[E0597]: `y` does not live long enough
 LL |     let x: &'static u32 = {
    |            ------------ type annotation requires that `y` is borrowed for `'static`
 LL |         let y = 42;
+   |             - binding `y` declared here
 LL |         &y
    |         ^^ borrowed value does not live long enough
 LL |     };
index 8d6a7f3721f0fab6e3431921ca493329585b4325..4585b22974cdbc91ae3f80dfaef8ae88853f34a7 100644 (file)
@@ -1,6 +1,8 @@
 error[E0505]: cannot move out of `a` because it is borrowed
   --> $DIR/drop-with-active-borrows-1.rs:4:10
    |
+LL |     let a = "".to_string();
+   |         - binding `a` declared here
 LL |     let b: Vec<&str> = a.lines().collect();
    |                        --------- borrow of `a` occurs here
 LL |     drop(a);
index 5d53405579d9d0b057ef7575113eab948bc02367..23d57634e8fd2e19e55b63c40b3f43736056f342 100644 (file)
@@ -1,6 +1,9 @@
 error[E0597]: `c_shortest` does not live long enough
   --> $DIR/dropck-eyepatch-extern-crate.rs:46:23
    |
+LL |         let (mut dt, mut dr, c_shortest): (Dt<_>, Dr<_>, Cell<_>);
+   |                              ---------- binding `c_shortest` declared here
+...
 LL |         dt = Dt("dt", &c_shortest);
    |                       ^^^^^^^^^^^ borrowed value does not live long enough
 ...
@@ -15,6 +18,9 @@ LL |     }
 error[E0597]: `c_shortest` does not live long enough
   --> $DIR/dropck-eyepatch-extern-crate.rs:68:32
    |
+LL |         let (mut pt, mut pr, c_shortest): (Pt<_, _>, Pr<_>, Cell<_>);
+   |                              ---------- binding `c_shortest` declared here
+...
 LL |         pt = Pt("pt", &c_long, &c_shortest);
    |                                ^^^^^^^^^^^ borrowed value does not live long enough
 ...
index 5055cdd8b2bf92d0792f0e5559207e8650cd22f1..a5d5136b5c578bd530e51577c48bc4b95087461b 100644 (file)
@@ -1,6 +1,9 @@
 error[E0597]: `c_shortest` does not live long enough
   --> $DIR/dropck-eyepatch-reorder.rs:64:23
    |
+LL |         let (mut dt, mut dr, c_shortest): (Dt<_>, Dr<_>, Cell<_>);
+   |                              ---------- binding `c_shortest` declared here
+...
 LL |         dt = Dt("dt", &c_shortest);
    |                       ^^^^^^^^^^^ borrowed value does not live long enough
 ...
@@ -15,6 +18,9 @@ LL |     }
 error[E0597]: `c_shortest` does not live long enough
   --> $DIR/dropck-eyepatch-reorder.rs:86:32
    |
+LL |         let (mut pt, mut pr, c_shortest): (Pt<_, _>, Pr<_>, Cell<_>);
+   |                              ---------- binding `c_shortest` declared here
+...
 LL |         pt = Pt("pt", &c_long, &c_shortest);
    |                                ^^^^^^^^^^^ borrowed value does not live long enough
 ...
index 21295e6c6019e4f6fb966fa76bf5f25e09c9cfbc..dc3f8c05e7396445176b4efc58f7739aeb0c3f20 100644 (file)
@@ -1,6 +1,9 @@
 error[E0597]: `c_shortest` does not live long enough
   --> $DIR/dropck-eyepatch.rs:88:23
    |
+LL |         let (mut dt, mut dr, c_shortest): (Dt<_>, Dr<_>, Cell<_>);
+   |                              ---------- binding `c_shortest` declared here
+...
 LL |         dt = Dt("dt", &c_shortest);
    |                       ^^^^^^^^^^^ borrowed value does not live long enough
 ...
@@ -15,6 +18,9 @@ LL |     }
 error[E0597]: `c_shortest` does not live long enough
   --> $DIR/dropck-eyepatch.rs:110:32
    |
+LL |         let (mut pt, mut pr, c_shortest): (Pt<_, _>, Pr<_>, Cell<_>);
+   |                              ---------- binding `c_shortest` declared here
+...
 LL |         pt = Pt("pt", &c_long, &c_shortest);
    |                                ^^^^^^^^^^^ borrowed value does not live long enough
 ...
index 854e29385a81bcc04785808f7410b4110d4d3d97..7d48e9fdcee3192c0a8266585cbe726cd8ab9cbb 100644 (file)
@@ -1,6 +1,8 @@
 error[E0597]: `v` does not live long enough
   --> $DIR/dropck-union.rs:37:18
    |
+LL |     let v : Wrap<C> = Wrap::new(C(Cell::new(None)));
+   |         - binding `v` declared here
 LL |     v.0.set(Some(&v));
    |                  ^^ borrowed value does not live long enough
 LL | }
index dc3fbed593b796d07925ca5089eb0b89bf3a1eb5..4d4f7b9df11799e4ede4246fd7602c93c98bfb6e 100644 (file)
@@ -2,7 +2,7 @@ error[E0597]: `o2` does not live long enough
   --> $DIR/dropck_trait_cycle_checked.rs:111:13
    |
 LL |     let (o1, o2, o3): (Box<dyn Obj>, Box<dyn Obj>, Box<dyn Obj>) = (O::new(), O::new(), O::new());
-   |                                                                     -------- cast requires that `o2` is borrowed for `'static`
+   |              -- binding `o2` declared here                          -------- cast requires that `o2` is borrowed for `'static`
 LL |     o1.set0(&o2);
    |             ^^^ borrowed value does not live long enough
 ...
@@ -13,7 +13,7 @@ error[E0597]: `o3` does not live long enough
   --> $DIR/dropck_trait_cycle_checked.rs:112:13
    |
 LL |     let (o1, o2, o3): (Box<dyn Obj>, Box<dyn Obj>, Box<dyn Obj>) = (O::new(), O::new(), O::new());
-   |                                                                     -------- cast requires that `o3` is borrowed for `'static`
+   |                  -- binding `o3` declared here                      -------- cast requires that `o3` is borrowed for `'static`
 LL |     o1.set0(&o2);
 LL |     o1.set1(&o3);
    |             ^^^ borrowed value does not live long enough
@@ -25,7 +25,7 @@ error[E0597]: `o2` does not live long enough
   --> $DIR/dropck_trait_cycle_checked.rs:113:13
    |
 LL |     let (o1, o2, o3): (Box<dyn Obj>, Box<dyn Obj>, Box<dyn Obj>) = (O::new(), O::new(), O::new());
-   |                                                                               -------- cast requires that `o2` is borrowed for `'static`
+   |              -- binding `o2` declared here                                    -------- cast requires that `o2` is borrowed for `'static`
 ...
 LL |     o2.set0(&o2);
    |             ^^^ borrowed value does not live long enough
@@ -37,7 +37,7 @@ error[E0597]: `o3` does not live long enough
   --> $DIR/dropck_trait_cycle_checked.rs:114:13
    |
 LL |     let (o1, o2, o3): (Box<dyn Obj>, Box<dyn Obj>, Box<dyn Obj>) = (O::new(), O::new(), O::new());
-   |                                                                               -------- cast requires that `o3` is borrowed for `'static`
+   |                  -- binding `o3` declared here                                -------- cast requires that `o3` is borrowed for `'static`
 ...
 LL |     o2.set1(&o3);
    |             ^^^ borrowed value does not live long enough
@@ -49,7 +49,7 @@ error[E0597]: `o1` does not live long enough
   --> $DIR/dropck_trait_cycle_checked.rs:115:13
    |
 LL |     let (o1, o2, o3): (Box<dyn Obj>, Box<dyn Obj>, Box<dyn Obj>) = (O::new(), O::new(), O::new());
-   |                                                                                         -------- cast requires that `o1` is borrowed for `'static`
+   |          -- binding `o1` declared here                                                  -------- cast requires that `o1` is borrowed for `'static`
 ...
 LL |     o3.set0(&o1);
    |             ^^^ borrowed value does not live long enough
@@ -61,7 +61,7 @@ error[E0597]: `o2` does not live long enough
   --> $DIR/dropck_trait_cycle_checked.rs:116:13
    |
 LL |     let (o1, o2, o3): (Box<dyn Obj>, Box<dyn Obj>, Box<dyn Obj>) = (O::new(), O::new(), O::new());
-   |                                                                                         -------- cast requires that `o2` is borrowed for `'static`
+   |              -- binding `o2` declared here                                              -------- cast requires that `o2` is borrowed for `'static`
 ...
 LL |     o3.set1(&o2);
    |             ^^^ borrowed value does not live long enough
index 957e98bbeee96c7e6e38569fa3ad5577a735be4e..1254250bcbd85cb91a8e43b53a5f47dcccc46c50 100644 (file)
@@ -3,7 +3,9 @@ error[E0597]: `f1` does not live long enough
    |
 LL | fn baz<'a>() {
    |        -- lifetime `'a` defined here
-...
+LL |     // With a vec of ints.
+LL |     let f1 = Fat { ptr: [1, 2, 3] };
+   |         -- binding `f1` declared here
 LL |     let f2: &Fat<[isize; 3]> = &f1;
    |                                ^^^ borrowed value does not live long enough
 LL |     let f3: &'a Fat<[isize]> = f2;
@@ -18,6 +20,8 @@ error[E0597]: `f1` does not live long enough
 LL | fn baz<'a>() {
    |        -- lifetime `'a` defined here
 ...
+LL |     let f1 = Fat { ptr: Foo };
+   |         -- binding `f1` declared here
 LL |     let f2: &Fat<Foo> = &f1;
    |                         ^^^ borrowed value does not live long enough
 LL |     let f3: &'a Fat<dyn Bar> = f2;
@@ -32,6 +36,8 @@ error[E0597]: `f1` does not live long enough
 LL | fn baz<'a>() {
    |        -- lifetime `'a` defined here
 ...
+LL |     let f1 = ([1, 2, 3],);
+   |         -- binding `f1` declared here
 LL |     let f2: &([isize; 3],) = &f1;
    |                              ^^^ borrowed value does not live long enough
 LL |     let f3: &'a ([isize],) = f2;
@@ -46,6 +52,8 @@ error[E0597]: `f1` does not live long enough
 LL | fn baz<'a>() {
    |        -- lifetime `'a` defined here
 ...
+LL |     let f1 = (Foo,);
+   |         -- binding `f1` declared here
 LL |     let f2: &(Foo,) = &f1;
    |                       ^^^ borrowed value does not live long enough
 LL |     let f3: &'a (dyn Bar,) = f2;
index fafe363eb47a6c05ecfa81883c917171d6eac6a6..2f02e3b1a613818270858b301bd3e55b7f720c85 100644 (file)
@@ -2,7 +2,7 @@ error[E0503]: cannot use `value` because it was mutably borrowed
   --> $DIR/E0503.rs:4:16
    |
 LL |     let _borrow = &mut value;
-   |                   ---------- borrow of `value` occurs here
+   |                   ---------- `value` is borrowed here
 LL |     let _sum = value + 1;
    |                ^^^^^ use of borrowed `value`
 LL |     _borrow.use_mut();
index e677e8916154240fb531b4e282c1871393e908de..20e16a5381061af846c2e6b9e8838a83e57f043e 100644 (file)
@@ -1,6 +1,8 @@
 error[E0505]: cannot move out of `fancy_num` because it is borrowed
   --> $DIR/E0504.rs:9:13
    |
+LL |     let fancy_num = FancyNum { num: 5 };
+   |         --------- binding `fancy_num` declared here
 LL |     let fancy_ref = &fancy_num;
    |                     ---------- borrow of `fancy_num` occurs here
 LL |
index bd3f37f54e0a88486417d2a7b786fcc1f2e42d7c..2ecb4a75c4382627f26865584ebfbd8af731fee7 100644 (file)
@@ -1,6 +1,9 @@
 error[E0505]: cannot move out of `x` because it is borrowed
   --> $DIR/E0505.rs:9:13
    |
+LL |     let x = Value{};
+   |         - binding `x` declared here
+LL |     {
 LL |         let _ref_to_val: &Value = &x;
    |                                   -- borrow of `x` occurs here
 LL |         eat(x);
index d70406b750afcf6cb04f1e3f7945b9e6ef9e68c0..17ad7c611f824eef6a68d59e56ba40eebbd68317 100644 (file)
@@ -2,9 +2,9 @@ error[E0506]: cannot assign to `fancy_num` because it is borrowed
   --> $DIR/E0506.rs:8:5
    |
 LL |     let fancy_ref = &fancy_num;
-   |                     ---------- borrow of `fancy_num` occurs here
+   |                     ---------- `fancy_num` is borrowed here
 LL |     fancy_num = FancyNum { num: 6 };
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ assignment to borrowed `fancy_num` occurs here
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `fancy_num` is assigned to here but it was already borrowed
 LL |
 LL |     println!("Num: {}, Ref: {}", fancy_num.num, fancy_ref.num);
    |                                                 ------------- borrow later used here
index b4a1180ad546c8903171c5e9c21434dbbb0d9ff0..82e3481b65a593ba17f019d7f546c46ba58bebd0 100644 (file)
@@ -1,6 +1,8 @@
 error[E0597]: `y` does not live long enough
   --> $DIR/E0597.rs:8:16
    |
+LL |     let y = 0;
+   |         - binding `y` declared here
 LL |     x.x = Some(&y);
    |                ^^ borrowed value does not live long enough
 LL |
diff --git a/tests/ui/feature-gates/feature-gate-dispatch-from-dyn-cell.rs b/tests/ui/feature-gates/feature-gate-dispatch-from-dyn-cell.rs
new file mode 100644 (file)
index 0000000..83366ea
--- /dev/null
@@ -0,0 +1,9 @@
+// Check that even though Cell: DispatchFromDyn it remains an invalid self parameter type
+
+use std::cell::Cell;
+
+trait Trait{
+    fn cell(self: Cell<&Self>); //~ ERROR invalid `self` parameter type: Cell<&Self>
+}
+
+fn main() {}
diff --git a/tests/ui/feature-gates/feature-gate-dispatch-from-dyn-cell.stderr b/tests/ui/feature-gates/feature-gate-dispatch-from-dyn-cell.stderr
new file mode 100644 (file)
index 0000000..ce06ce9
--- /dev/null
@@ -0,0 +1,12 @@
+error[E0307]: invalid `self` parameter type: Cell<&Self>
+  --> $DIR/feature-gate-dispatch-from-dyn-cell.rs:6:19
+   |
+LL |     fn cell(self: Cell<&Self>);
+   |                   ^^^^^^^^^^^
+   |
+   = note: type of `self` must be `Self` or a type that dereferences to it
+   = help: consider changing to `self`, `&self`, `&mut self`, `self: Box<Self>`, `self: Rc<Self>`, `self: Arc<Self>`, or `self: Pin<P>` (where P is one of the previous types except `Self`)
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0307`.
diff --git a/tests/ui/feature-gates/feature-gate-dispatch-from-dyn-missing-impl.rs b/tests/ui/feature-gates/feature-gate-dispatch-from-dyn-missing-impl.rs
new file mode 100644 (file)
index 0000000..23857cb
--- /dev/null
@@ -0,0 +1,35 @@
+// Check that a self parameter type requires a DispatchFromDyn impl to be object safe
+
+#![feature(arbitrary_self_types, unsize, coerce_unsized)]
+
+use std::{
+    marker::Unsize,
+    ops::{CoerceUnsized, Deref},
+};
+
+struct Ptr<T: ?Sized>(Box<T>);
+
+impl<T: ?Sized> Deref for Ptr<T> {
+    type Target = T;
+
+    fn deref(&self) -> &T {
+        &*self.0
+    }
+}
+
+impl<T: Unsize<U> + ?Sized, U: ?Sized> CoerceUnsized<Ptr<U>> for Ptr<T> {}
+// Because this impl is missing the coercion below fails.
+// impl<T: Unsize<U> + ?Sized, U: ?Sized> DispatchFromDyn<Ptr<U>> for Ptr<T> {}
+
+trait Trait {
+    fn ptr(self: Ptr<Self>);
+}
+impl Trait for i32 {
+    fn ptr(self: Ptr<Self>) {}
+}
+
+fn main() {
+    Ptr(Box::new(4)) as Ptr<dyn Trait>;
+    //~^ ERROR the trait `Trait` cannot be made into an object
+    //~^^ ERROR the trait `Trait` cannot be made into an object
+}
diff --git a/tests/ui/feature-gates/feature-gate-dispatch-from-dyn-missing-impl.stderr b/tests/ui/feature-gates/feature-gate-dispatch-from-dyn-missing-impl.stderr
new file mode 100644 (file)
index 0000000..d81eade
--- /dev/null
@@ -0,0 +1,45 @@
+error[E0038]: the trait `Trait` cannot be made into an object
+  --> $DIR/feature-gate-dispatch-from-dyn-missing-impl.rs:32:25
+   |
+LL |     fn ptr(self: Ptr<Self>);
+   |                  --------- help: consider changing method `ptr`'s `self` parameter to be `&self`: `&Self`
+...
+LL |     Ptr(Box::new(4)) as Ptr<dyn Trait>;
+   |                         ^^^^^^^^^^^^^^ `Trait` cannot be made into an object
+   |
+note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+  --> $DIR/feature-gate-dispatch-from-dyn-missing-impl.rs:25:18
+   |
+LL | trait Trait {
+   |       ----- this trait cannot be made into an object...
+LL |     fn ptr(self: Ptr<Self>);
+   |                  ^^^^^^^^^ ...because method `ptr`'s `self` parameter cannot be dispatched on
+
+error[E0038]: the trait `Trait` cannot be made into an object
+  --> $DIR/feature-gate-dispatch-from-dyn-missing-impl.rs:32:5
+   |
+LL |     fn ptr(self: Ptr<Self>);
+   |                  --------- help: consider changing method `ptr`'s `self` parameter to be `&self`: `&Self`
+...
+LL |     Ptr(Box::new(4)) as Ptr<dyn Trait>;
+   |     ^^^^^^^^^^^^^^^^ `Trait` cannot be made into an object
+   |
+note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+  --> $DIR/feature-gate-dispatch-from-dyn-missing-impl.rs:25:18
+   |
+LL | trait Trait {
+   |       ----- this trait cannot be made into an object...
+LL |     fn ptr(self: Ptr<Self>);
+   |                  ^^^^^^^^^ ...because method `ptr`'s `self` parameter cannot be dispatched on
+note: required for `Ptr<{integer}>` to implement `CoerceUnsized<Ptr<dyn Trait>>`
+  --> $DIR/feature-gate-dispatch-from-dyn-missing-impl.rs:20:40
+   |
+LL | impl<T: Unsize<U> + ?Sized, U: ?Sized> CoerceUnsized<Ptr<U>> for Ptr<T> {}
+   |         ---------                      ^^^^^^^^^^^^^^^^^^^^^     ^^^^^^
+   |         |
+   |         unsatisfied trait bound introduced here
+   = note: required by cast to type `Ptr<dyn Trait>`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0038`.
index df838cb11810578e8ec10274324269c48750cf43..b4e71e75fdb9a196a556be0afb8eafffd5bf869d 100644 (file)
@@ -19,6 +19,8 @@ LL |     let x = f == g;
    |
    = note: expected fn item `fn() {f}`
               found fn item `fn() {g}`
+   = note: different fn items have unique types, even if their signatures are the same
+   = help: consider casting both fn items to fn pointers using `as fn()`
 
 error: aborting due to 2 previous errors
 
index 1831e6cbf10507ecb102cb432c32feb1c856da16..b6ebc867d284be59a383316218a6f644f455540a 100644 (file)
@@ -1,13 +1,22 @@
 // Test that the types of distinct fn items are not compatible by
 // default. See also `run-pass/fn-item-type-*.rs`.
 
-fn foo<T>(x: isize) -> isize { x * 2 }
-fn bar<T>(x: isize) -> isize { x * 4 }
+fn foo<T>(x: isize) -> isize {
+    x * 2
+}
+fn bar<T>(x: isize) -> isize {
+    x * 4
+}
 
-fn eq<T>(x: T, y: T) { }
+fn eq<T>(x: T, y: T) {}
 
-trait Foo { fn foo() { /* this is a default fn */ } }
-impl<T> Foo for T { /* `foo` is still default here */ }
+trait Foo {
+    fn foo() { /* this is a default fn */
+    }
+}
+impl<T> Foo for T {
+    /* `foo` is still default here */
+}
 
 fn main() {
     eq(foo::<u8>, bar::<u8>);
@@ -15,39 +24,29 @@ fn main() {
     //~| expected fn item `fn(_) -> _ {foo::<u8>}`
     //~| found fn item `fn(_) -> _ {bar::<u8>}`
     //~| expected fn item, found a different fn item
-    //~| different `fn` items always have unique types, even if their signatures are the same
-    //~| change the expected type to be function pointer
-    //~| if the expected type is due to type inference, cast the expected `fn` to a function pointer
+    //~| different fn items have unique types, even if their signatures are the same
 
     eq(foo::<u8>, foo::<i8>);
     //~^ ERROR mismatched types
     //~| expected `u8`, found `i8`
-    //~| different `fn` items always have unique types, even if their signatures are the same
-    //~| change the expected type to be function pointer
-    //~| if the expected type is due to type inference, cast the expected `fn` to a function pointer
+    //~| different fn items have unique types, even if their signatures are the same
 
     eq(bar::<String>, bar::<Vec<u8>>);
     //~^ ERROR mismatched types
     //~| found fn item `fn(_) -> _ {bar::<Vec<u8>>}`
     //~| expected struct `String`, found struct `Vec`
-    //~| different `fn` items always have unique types, even if their signatures are the same
-    //~| change the expected type to be function pointer
-    //~| if the expected type is due to type inference, cast the expected `fn` to a function pointer
+    //~| different fn items have unique types, even if their signatures are the same
 
     // Make sure we distinguish between trait methods correctly.
     eq(<u8 as Foo>::foo, <u16 as Foo>::foo);
     //~^ ERROR mismatched types
     //~| expected `u8`, found `u16`
-    //~| different `fn` items always have unique types, even if their signatures are the same
-    //~| change the expected type to be function pointer
-    //~| if the expected type is due to type inference, cast the expected `fn` to a function pointer
+    //~| different fn items have unique types, even if their signatures are the same
 
     eq(foo::<u8>, bar::<u8> as fn(isize) -> isize);
     //~^ ERROR mismatched types
     //~| found fn pointer `fn(_) -> _`
     //~| expected fn item, found fn pointer
-    //~| change the expected type to be function pointer
-    //~| if the expected type is due to type inference, cast the expected `fn` to a function pointer
 
     eq(foo::<u8> as fn(isize) -> isize, bar::<u8>); // ok!
 }
index f03a47d5c2c75c4727ba65d9685265b190159a0f..9d41243ef11917479aca7c97468b5e5768578352 100644 (file)
@@ -1,5 +1,5 @@
 error[E0308]: mismatched types
-  --> $DIR/fn-item-type.rs:13:19
+  --> $DIR/fn-item-type.rs:22:19
    |
 LL |     eq(foo::<u8>, bar::<u8>);
    |     --            ^^^^^^^^^ expected fn item, found a different fn item
@@ -8,17 +8,16 @@ LL |     eq(foo::<u8>, bar::<u8>);
    |
    = note: expected fn item `fn(_) -> _ {foo::<u8>}`
               found fn item `fn(_) -> _ {bar::<u8>}`
-   = note: different `fn` items always have unique types, even if their signatures are the same
-   = help: change the expected type to be function pointer `fn(isize) -> isize`
-   = help: if the expected type is due to type inference, cast the expected `fn` to a function pointer: `foo::<u8> as fn(isize) -> isize`
+   = note: different fn items have unique types, even if their signatures are the same
 note: function defined here
-  --> $DIR/fn-item-type.rs:7:4
+  --> $DIR/fn-item-type.rs:11:4
    |
-LL | fn eq<T>(x: T, y: T) { }
+LL | fn eq<T>(x: T, y: T) {}
    |    ^^          ----
+   = help: consider casting both fn items to fn pointers using `as fn(isize) -> isize`
 
 error[E0308]: mismatched types
-  --> $DIR/fn-item-type.rs:22:19
+  --> $DIR/fn-item-type.rs:29:19
    |
 LL |     eq(foo::<u8>, foo::<i8>);
    |     --            ^^^^^^^^^ expected `u8`, found `i8`
@@ -27,17 +26,16 @@ LL |     eq(foo::<u8>, foo::<i8>);
    |
    = note: expected fn item `fn(_) -> _ {foo::<u8>}`
               found fn item `fn(_) -> _ {foo::<i8>}`
-   = note: different `fn` items always have unique types, even if their signatures are the same
-   = help: change the expected type to be function pointer `fn(isize) -> isize`
-   = help: if the expected type is due to type inference, cast the expected `fn` to a function pointer: `foo::<u8> as fn(isize) -> isize`
+   = note: different fn items have unique types, even if their signatures are the same
 note: function defined here
-  --> $DIR/fn-item-type.rs:7:4
+  --> $DIR/fn-item-type.rs:11:4
    |
-LL | fn eq<T>(x: T, y: T) { }
+LL | fn eq<T>(x: T, y: T) {}
    |    ^^          ----
+   = help: consider casting both fn items to fn pointers using `as fn(isize) -> isize`
 
 error[E0308]: mismatched types
-  --> $DIR/fn-item-type.rs:29:23
+  --> $DIR/fn-item-type.rs:34:23
    |
 LL |     eq(bar::<String>, bar::<Vec<u8>>);
    |     --                ^^^^^^^^^^^^^^ expected struct `String`, found struct `Vec`
@@ -46,17 +44,16 @@ LL |     eq(bar::<String>, bar::<Vec<u8>>);
    |
    = note: expected fn item `fn(_) -> _ {bar::<String>}`
               found fn item `fn(_) -> _ {bar::<Vec<u8>>}`
-   = note: different `fn` items always have unique types, even if their signatures are the same
-   = help: change the expected type to be function pointer `fn(isize) -> isize`
-   = help: if the expected type is due to type inference, cast the expected `fn` to a function pointer: `bar::<String> as fn(isize) -> isize`
+   = note: different fn items have unique types, even if their signatures are the same
 note: function defined here
-  --> $DIR/fn-item-type.rs:7:4
+  --> $DIR/fn-item-type.rs:11:4
    |
-LL | fn eq<T>(x: T, y: T) { }
+LL | fn eq<T>(x: T, y: T) {}
    |    ^^          ----
+   = help: consider casting both fn items to fn pointers using `as fn(isize) -> isize`
 
 error[E0308]: mismatched types
-  --> $DIR/fn-item-type.rs:38:26
+  --> $DIR/fn-item-type.rs:41:26
    |
 LL |     eq(<u8 as Foo>::foo, <u16 as Foo>::foo);
    |     --                   ^^^^^^^^^^^^^^^^^ expected `u8`, found `u16`
@@ -65,17 +62,16 @@ LL |     eq(<u8 as Foo>::foo, <u16 as Foo>::foo);
    |
    = note: expected fn item `fn() {<u8 as Foo>::foo}`
               found fn item `fn() {<u16 as Foo>::foo}`
-   = note: different `fn` items always have unique types, even if their signatures are the same
-   = help: change the expected type to be function pointer `fn()`
-   = help: if the expected type is due to type inference, cast the expected `fn` to a function pointer: `<u8 as Foo>::foo as fn()`
+   = note: different fn items have unique types, even if their signatures are the same
 note: function defined here
-  --> $DIR/fn-item-type.rs:7:4
+  --> $DIR/fn-item-type.rs:11:4
    |
-LL | fn eq<T>(x: T, y: T) { }
+LL | fn eq<T>(x: T, y: T) {}
    |    ^^          ----
+   = help: consider casting both fn items to fn pointers using `as fn()`
 
 error[E0308]: mismatched types
-  --> $DIR/fn-item-type.rs:45:19
+  --> $DIR/fn-item-type.rs:46:19
    |
 LL |     eq(foo::<u8>, bar::<u8> as fn(isize) -> isize);
    |     --            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected fn item, found fn pointer
@@ -84,12 +80,11 @@ LL |     eq(foo::<u8>, bar::<u8> as fn(isize) -> isize);
    |
    = note: expected fn item `fn(_) -> _ {foo::<u8>}`
            found fn pointer `fn(_) -> _`
-   = help: change the expected type to be function pointer `fn(isize) -> isize`
-   = help: if the expected type is due to type inference, cast the expected `fn` to a function pointer: `foo::<u8> as fn(isize) -> isize`
+   = help: consider casting the fn item to a fn pointer: `foo::<u8> as fn(isize) -> isize`
 note: function defined here
-  --> $DIR/fn-item-type.rs:7:4
+  --> $DIR/fn-item-type.rs:11:4
    |
-LL | fn eq<T>(x: T, y: T) { }
+LL | fn eq<T>(x: T, y: T) {}
    |    ^^          ----
 
 error: aborting due to 5 previous errors
diff --git a/tests/ui/fn/fn-pointer-mismatch.rs b/tests/ui/fn/fn-pointer-mismatch.rs
new file mode 100644 (file)
index 0000000..0597478
--- /dev/null
@@ -0,0 +1,56 @@
+fn foo(x: u32) -> u32 {
+    x * 2
+}
+
+fn bar(x: u32) -> u32 {
+    x * 3
+}
+
+// original example from Issue #102608
+fn foobar(n: u32) -> u32 {
+    let g = if n % 2 == 0 { &foo } else { &bar };
+    //~^ ERROR `if` and `else` have incompatible types
+    //~| different fn items have unique types, even if their signatures are the same
+    g(n)
+}
+
+fn main() {
+    assert_eq!(foobar(7), 21);
+    assert_eq!(foobar(8), 16);
+
+    // general mismatch of fn item types
+    let mut a = foo;
+    a = bar;
+    //~^ ERROR mismatched types
+    //~| expected fn item `fn(_) -> _ {foo}`
+    //~| found fn item `fn(_) -> _ {bar}`
+    //~| different fn items have unique types, even if their signatures are the same
+
+    // display note even when boxed
+    let mut b = Box::new(foo);
+    b = Box::new(bar);
+    //~^ ERROR mismatched types
+    //~| different fn items have unique types, even if their signatures are the same
+
+    // suggest removing reference
+    let c: fn(u32) -> u32 = &foo;
+    //~^ ERROR mismatched types
+    //~| expected fn pointer `fn(u32) -> u32`
+    //~| found reference `&fn(u32) -> u32 {foo}`
+
+    // suggest using reference
+    let d: &fn(u32) -> u32 = foo;
+    //~^ ERROR mismatched types
+    //~| expected reference `&fn(u32) -> u32`
+    //~| found fn item `fn(u32) -> u32 {foo}`
+
+    // suggest casting with reference
+    let e: &fn(u32) -> u32 = &foo;
+    //~^ ERROR mismatched types
+    //~| expected reference `&fn(u32) -> u32`
+    //~| found reference `&fn(u32) -> u32 {foo}`
+
+    // OK
+    let mut z: fn(u32) -> u32 = foo as fn(u32) -> u32;
+    z = bar;
+}
diff --git a/tests/ui/fn/fn-pointer-mismatch.stderr b/tests/ui/fn/fn-pointer-mismatch.stderr
new file mode 100644 (file)
index 0000000..e0bd60f
--- /dev/null
@@ -0,0 +1,84 @@
+error[E0308]: `if` and `else` have incompatible types
+  --> $DIR/fn-pointer-mismatch.rs:11:43
+   |
+LL |     let g = if n % 2 == 0 { &foo } else { &bar };
+   |                             ----          ^^^^ expected fn item, found a different fn item
+   |                             |
+   |                             expected because of this
+   |
+   = note: expected reference `&fn(u32) -> u32 {foo}`
+              found reference `&fn(u32) -> u32 {bar}`
+   = note: different fn items have unique types, even if their signatures are the same
+   = help: consider casting both fn items to fn pointers using `as fn(u32) -> u32`
+
+error[E0308]: mismatched types
+  --> $DIR/fn-pointer-mismatch.rs:23:9
+   |
+LL |     let mut a = foo;
+   |                 --- expected due to this value
+LL |     a = bar;
+   |         ^^^ expected fn item, found a different fn item
+   |
+   = note: expected fn item `fn(_) -> _ {foo}`
+              found fn item `fn(_) -> _ {bar}`
+   = note: different fn items have unique types, even if their signatures are the same
+   = help: consider casting both fn items to fn pointers using `as fn(u32) -> u32`
+
+error[E0308]: mismatched types
+  --> $DIR/fn-pointer-mismatch.rs:31:18
+   |
+LL |     b = Box::new(bar);
+   |         -------- ^^^ expected fn item, found a different fn item
+   |         |
+   |         arguments to this function are incorrect
+   |
+   = note: expected fn item `fn(_) -> _ {foo}`
+              found fn item `fn(_) -> _ {bar}`
+   = note: different fn items have unique types, even if their signatures are the same
+note: associated function defined here
+  --> $SRC_DIR/alloc/src/boxed.rs:LL:COL
+   = help: consider casting both fn items to fn pointers using `as fn(u32) -> u32`
+
+error[E0308]: mismatched types
+  --> $DIR/fn-pointer-mismatch.rs:36:29
+   |
+LL |     let c: fn(u32) -> u32 = &foo;
+   |            --------------   ^^^^
+   |            |                |
+   |            |                expected fn pointer, found reference
+   |            |                help: consider removing the reference: `foo`
+   |            expected due to this
+   |
+   = note: expected fn pointer `fn(u32) -> u32`
+               found reference `&fn(u32) -> u32 {foo}`
+
+error[E0308]: mismatched types
+  --> $DIR/fn-pointer-mismatch.rs:42:30
+   |
+LL |     let d: &fn(u32) -> u32 = foo;
+   |            ---------------   ^^^
+   |            |                 |
+   |            |                 expected `&fn(u32) -> u32`, found fn item
+   |            |                 help: consider using a reference: `&foo`
+   |            expected due to this
+   |
+   = note: expected reference `&fn(u32) -> u32`
+                found fn item `fn(u32) -> u32 {foo}`
+
+error[E0308]: mismatched types
+  --> $DIR/fn-pointer-mismatch.rs:48:30
+   |
+LL |     let e: &fn(u32) -> u32 = &foo;
+   |            ---------------   ^^^^
+   |            |                 |
+   |            |                 expected fn pointer, found fn item
+   |            |                 help: consider casting to a fn pointer: `&(foo as fn(u32) -> u32)`
+   |            expected due to this
+   |
+   = note: expected reference `&fn(u32) -> u32`
+              found reference `&fn(u32) -> u32 {foo}`
+   = note: fn items are distinct from fn pointers
+
+error: aborting due to 6 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
index fcbaa91d19f82d1a1833c8eaa96705792003c50b..4df639232a332436b0d122f23980c199a8b5e5b4 100644 (file)
@@ -1,6 +1,8 @@
 error[E0505]: cannot move out of `x` because it is borrowed
   --> $DIR/implied-bounds-unnorm-associated-type-4.rs:21:10
    |
+LL |     let x = String::from("Hello World!");
+   |         - binding `x` declared here
 LL |     let y = f(&x, ());
    |               -- borrow of `x` occurs here
 LL |     drop(x);
index e35f46e4439a90b1c9e94ac8396b8a2077b9851b..d417f28839368978f54d413405094cac3147a068 100644 (file)
@@ -1,6 +1,8 @@
 error[E0505]: cannot move out of `x` because it is borrowed
   --> $DIR/implied-bounds-unnorm-associated-type.rs:20:10
    |
+LL |     let x = String::from("Hello World!");
+   |         - binding `x` declared here
 LL |     let y = f(&x, ());
    |               -- borrow of `x` occurs here
 LL |     drop(x);
index 7bb188352d7a27b7631deb78e7b5fe20194c3377..b9a3a124acb61d91be4246ad201094fdbf452786 100644 (file)
@@ -1,6 +1,9 @@
 error[E0597]: `*cell` does not live long enough
   --> $DIR/dropck.rs:10:40
    |
+LL |     let (mut gen, cell);
+   |                   ---- binding `cell` declared here
+LL |     cell = Box::new(RefCell::new(0));
 LL |     let ref_ = Box::leak(Box::new(Some(cell.borrow_mut())));
    |                                        ^^^^^^^^^^^^^^^^^ borrowed value does not live long enough
 ...
index 21026f45cb823375f9cc94400a0aed20da7ef085..9def544e3d25c5119a96e5e94035b5afa941f411 100644 (file)
@@ -40,6 +40,7 @@ fn test1() {
     require_send(send_gen);
     //~^ ERROR generator cannot be sent between threads
     //~| NOTE not `Send`
+    //~| NOTE use `std::sync::RwLock` instead
 }
 
 pub fn make_gen2<T>(t: T) -> impl Generator<Return = T> {
@@ -66,6 +67,7 @@ fn test2() {
     //~| NOTE required for
     //~| NOTE required by a bound introduced by this call
     //~| NOTE captures the following types
+    //~| NOTE use `std::sync::RwLock` instead
 }
 
 fn main() {}
index eb99d42c9206805a90800898f75eb5ffd8ab5ed5..b42bc93d01f662b2dd4ae3efb8df774dc1a72e6d 100644 (file)
@@ -5,6 +5,7 @@ LL |     require_send(send_gen);
    |                  ^^^^^^^^ generator is not `Send`
    |
    = help: the trait `Sync` is not implemented for `RefCell<i32>`
+   = note: if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` instead
 note: generator is not `Send` as this value is used across a yield
   --> $DIR/issue-68112.rs:36:9
    |
@@ -23,7 +24,7 @@ LL | fn require_send(_: impl Send) {}
    |                         ^^^^ required by this bound in `require_send`
 
 error[E0277]: `RefCell<i32>` cannot be shared between threads safely
-  --> $DIR/issue-68112.rs:63:18
+  --> $DIR/issue-68112.rs:64:18
    |
 LL |     require_send(send_gen);
    |     ------------ ^^^^^^^^ `RefCell<i32>` cannot be shared between threads safely
@@ -31,25 +32,26 @@ LL |     require_send(send_gen);
    |     required by a bound introduced by this call
    |
    = help: the trait `Sync` is not implemented for `RefCell<i32>`
+   = note: if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` instead
    = note: required for `Arc<RefCell<i32>>` to implement `Send`
 note: required because it's used within this generator
-  --> $DIR/issue-68112.rs:48:5
+  --> $DIR/issue-68112.rs:49:5
    |
 LL |     || {
    |     ^^
 note: required because it appears within the type `impl Generator<Return = Arc<RefCell<i32>>>`
-  --> $DIR/issue-68112.rs:45:30
+  --> $DIR/issue-68112.rs:46:30
    |
 LL | pub fn make_gen2<T>(t: T) -> impl Generator<Return = T> {
    |                              ^^^^^^^^^^^^^^^^^^^^^^^^^^
 note: required because it appears within the type `impl Generator<Return = Arc<RefCell<i32>>>`
-  --> $DIR/issue-68112.rs:53:34
+  --> $DIR/issue-68112.rs:54:34
    |
 LL | fn make_non_send_generator2() -> impl Generator<Return = Arc<RefCell<i32>>> {
    |                                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    = note: required because it captures the following types: `impl Generator<Return = Arc<RefCell<i32>>>`, `()`
 note: required because it's used within this generator
-  --> $DIR/issue-68112.rs:59:20
+  --> $DIR/issue-68112.rs:60:20
    |
 LL |     let send_gen = || {
    |                    ^^
index a821c57b923a097bdb4770b167e6c568a6acbd51..1711df729b8c087634f282025dc66e5a50bdb931 100644 (file)
@@ -12,6 +12,7 @@ LL | |     });
    | |_____^ `Cell<i32>` cannot be shared between threads safely
    |
    = help: the trait `Sync` is not implemented for `Cell<i32>`
+   = note: if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` or `std::sync::atomic::AtomicI32` instead
    = note: required for `&Cell<i32>` to implement `Send`
 note: required because it's used within this generator
   --> $DIR/not-send-sync.rs:16:17
@@ -36,6 +37,7 @@ LL | |     });
    | |_____^ generator is not `Sync`
    |
    = help: within `[generator@$DIR/not-send-sync.rs:9:17: 9:19]`, the trait `Sync` is not implemented for `Cell<i32>`
+   = note: if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` or `std::sync::atomic::AtomicI32` instead
 note: generator is not `Sync` as this value is used across a yield
   --> $DIR/not-send-sync.rs:12:9
    |
index ebf35be581c60a1c3478ee964f57a1badb32dad1..45d018b8ebad5066d9f0043ef68f6366c730f535 100644 (file)
@@ -5,6 +5,7 @@ LL |     require_send(send_gen);
    |                  ^^^^^^^^ generator is not `Send`
    |
    = help: the trait `Sync` is not implemented for `RefCell<i32>`
+   = note: if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` instead
 note: generator is not `Send` as this value is used across a yield
   --> $DIR/generator-print-verbose-1.rs:35:9
    |
@@ -29,6 +30,7 @@ LL |     require_send(send_gen);
    |     required by a bound introduced by this call
    |
    = help: the trait `Sync` is not implemented for `RefCell<i32>`
+   = note: if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` instead
    = note: required for `Arc<RefCell<i32>>` to implement `Send`
 note: required because it's used within this generator
   --> $DIR/generator-print-verbose-1.rs:42:5
index 909e49c38b8d18e42e7ba3f56f5e242788b6aa10..59112ce0a79e60234354effa8bba52b73c2c4f5f 100644 (file)
@@ -12,6 +12,7 @@ LL | |     });
    | |_____^ `Cell<i32>` cannot be shared between threads safely
    |
    = help: the trait `Sync` is not implemented for `Cell<i32>`
+   = note: if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` or `std::sync::atomic::AtomicI32` instead
    = note: required for `&'_#4r Cell<i32>` to implement `Send`
 note: required because it's used within this generator
   --> $DIR/generator-print-verbose-2.rs:19:17
@@ -36,6 +37,7 @@ LL | |     });
    | |_____^ generator is not `Sync`
    |
    = help: within `[main::{closure#0} upvar_tys=() {Cell<i32>, ()}]`, the trait `Sync` is not implemented for `Cell<i32>`
+   = note: if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` or `std::sync::atomic::AtomicI32` instead
 note: generator is not `Sync` as this value is used across a yield
   --> $DIR/generator-print-verbose-2.rs:15:9
    |
index cacc973077ce72f9c918db182135d505b0a77aac..b93ee37987f272b96888c48506c2c8d2cc534a26 100644 (file)
@@ -4,6 +4,7 @@ error[E0597]: `a` does not live long enough
 LL | fn bug<'a, T: ?Sized + Fun<F<'a> = [u8]>>(_ : Box<T>) -> &'static T::F<'a> {
    |        -- lifetime `'a` defined here
 LL |     let a = [0; 1];
+   |         - binding `a` declared here
 LL |     let _x = T::identity(&a);
    |              ------------^^-
    |              |           |
index 4886a3c8bad62925aec0d2e0500d52c5ba7a3c30..25af011e3fc410049cc0a39322f06044556a0431 100644 (file)
@@ -2,9 +2,9 @@ error[E0506]: cannot assign to `x` because it is borrowed
   --> $DIR/hrtb-identity-fn-borrows.rs:14:5
    |
 LL |     let y = f.call(&x);
-   |                    -- borrow of `x` occurs here
+   |                    -- `x` is borrowed here
 LL |     x = 5;
-   |     ^^^^^ assignment to borrowed `x` occurs here
+   |     ^^^^^ `x` is assigned to here but it was already borrowed
 ...
 LL |     drop(y);
    |          - borrow later used here
index 601e53b7694596631c84c67ada9e54e958519058..b9b8d00ce308b7463efac35c5c51a5725380f309 100644 (file)
@@ -4,6 +4,7 @@ error[E0597]: `bar` does not live long enough
 LL |         let x = {
    |             - borrow later stored here
 LL |             let bar = 22;
+   |                 --- binding `bar` declared here
 LL |             Foo::new(&bar).into()
    |                      ^^^^ borrowed value does not live long enough
 LL |
@@ -16,6 +17,7 @@ error[E0597]: `y` does not live long enough
 LL |         let x = {
    |             - borrow later stored here
 LL |             let y = ();
+   |                 - binding `y` declared here
 LL |             foo(&y)
    |                 ^^ borrowed value does not live long enough
 LL |
@@ -28,6 +30,7 @@ error[E0597]: `y` does not live long enough
 LL |         let x = {
    |             - borrow later stored here
 LL |             let y = ();
+   |                 - binding `y` declared here
 LL |             foo(&y)
    |                 ^^ borrowed value does not live long enough
 LL |
index d0249e74f39e966939434ac403c5ea4417e2740e..307899297bc01664fa71c38d2f01b42e30130013 100644 (file)
@@ -1,6 +1,8 @@
 error[E0597]: `x` does not live long enough
   --> $DIR/assoc-ty-wf-used-to-get-assoc-ty.rs:24:31
    |
+LL |     let x: u8 = 3;
+   |         - binding `x` declared here
 LL |     let _: &'static u8 = test(&x, &&3);
    |                          -----^^------
    |                          |    |
index a23f7c9a796c53b1a74726d14c1efccdcadb12f0..443fcf89c4e11d1aa8c5f6c0ee2a02e4b41bcac3 100644 (file)
@@ -4,6 +4,7 @@ error[E0597]: `y` does not live long enough
 LL | fn foo<'a>() {
    |        -- lifetime `'a` defined here
 LL |     let y = ();
+   |         - binding `y` declared here
 LL |     equate(InvariantRef::new(&y), const { InvariantRef::<'a>::NEW });
    |            ------------------^^-
    |            |                 |
diff --git a/tests/ui/io-checks/inaccessbile-temp-dir.rs b/tests/ui/io-checks/inaccessbile-temp-dir.rs
new file mode 100644 (file)
index 0000000..9c0aa01
--- /dev/null
@@ -0,0 +1,39 @@
+// Issue #66530: We would ICE if someone compiled with `-o /dev/null`,
+// because we would try to generate auxiliary files in `/dev/` (which
+// at least the OS X file system rejects).
+//
+// An attempt to `-o` into a directory we cannot write into should indeed
+// be an error; but not an ICE.
+//
+// However, some folks run tests as root, which can write `/dev/` and end
+// up clobbering `/dev/null`. Instead we'll use a non-existent path, which
+// also used to ICE, but even root can't magically write there.
+
+// compile-flags: -Z temps-dir=/does-not-exist/output
+
+// The error-pattern check occurs *before* normalization, and the error patterns
+// are wildly different between build environments. So this is a cop-out (and we
+// rely on the checking of the normalized stderr output as our actual
+// "verification" of the diagnostic).
+
+// error-pattern: error
+
+// On Mac OS X, we get an error like the below
+// normalize-stderr-test "failed to write bytecode to /does-not-exist/output.non_ice_error_on_worker_io_fail.*" -> "io error modifying /does-not-exist/"
+
+// On Linux, we get an error like the below
+// normalize-stderr-test "couldn't create a temp dir.*" -> "io error modifying /does-not-exist/"
+
+// ignore-windows - this is a unix-specific test
+// ignore-emscripten - the file-system issues do not replicate here
+// ignore-wasm - the file-system issues do not replicate here
+// ignore-arm - the file-system issues do not replicate here, at least on armhf-gnu
+
+#![crate_type = "lib"]
+#![cfg_attr(not(feature = "std"), no_std)]
+pub mod task {
+    pub mod __internal {
+        use crate::task::Waker;
+    }
+    pub use core::task::Waker;
+}
diff --git a/tests/ui/io-checks/inaccessbile-temp-dir.stderr b/tests/ui/io-checks/inaccessbile-temp-dir.stderr
new file mode 100644 (file)
index 0000000..2fc5f93
--- /dev/null
@@ -0,0 +1,4 @@
+error: failed to find or create the directory specified by `--temps-dir`
+
+error: aborting due to previous error
+
diff --git a/tests/ui/io-checks/non-ice-error-on-worker-io-fail.rs b/tests/ui/io-checks/non-ice-error-on-worker-io-fail.rs
new file mode 100644 (file)
index 0000000..134e7d4
--- /dev/null
@@ -0,0 +1,40 @@
+// Issue #66530: We would ICE if someone compiled with `-o /dev/null`,
+// because we would try to generate auxiliary files in `/dev/` (which
+// at least the OS X file system rejects).
+//
+// An attempt to `-o` into a directory we cannot write into should indeed
+// be an error; but not an ICE.
+//
+// However, some folks run tests as root, which can write `/dev/` and end
+// up clobbering `/dev/null`. Instead we'll use a non-existent path, which
+// also used to ICE, but even root can't magically write there.
+
+// compile-flags: -o /does-not-exist/output
+
+// The error-pattern check occurs *before* normalization, and the error patterns
+// are wildly different between build environments. So this is a cop-out (and we
+// rely on the checking of the normalized stderr output as our actual
+// "verification" of the diagnostic).
+
+// error-pattern: error
+
+// On Mac OS X, we get an error like the below
+// normalize-stderr-test "failed to write bytecode to /does-not-exist/output.non_ice_error_on_worker_io_fail.*" -> "io error modifying /does-not-exist/"
+
+// On Linux, we get an error like the below
+// normalize-stderr-test "couldn't create a temp dir.*" -> "io error modifying /does-not-exist/"
+
+// ignore-windows - this is a unix-specific test
+// ignore-emscripten - the file-system issues do not replicate here
+// ignore-wasm - the file-system issues do not replicate here
+// ignore-arm - the file-system issues do not replicate here, at least on armhf-gnu
+
+#![crate_type="lib"]
+
+#![cfg_attr(not(feature = "std"), no_std)]
+pub mod task {
+    pub mod __internal {
+        use crate::task::Waker;
+    }
+    pub use core::task::Waker;
+}
diff --git a/tests/ui/io-checks/non-ice-error-on-worker-io-fail.stderr b/tests/ui/io-checks/non-ice-error-on-worker-io-fail.stderr
new file mode 100644 (file)
index 0000000..edadecf
--- /dev/null
@@ -0,0 +1,6 @@
+warning: ignoring --out-dir flag due to -o flag
+
+error: io error modifying /does-not-exist/
+
+error: aborting due to previous error; 1 warning emitted
+
index fb4ecab362db1f61ffb9a7880f7a57a85a114583..db5d064379a76a40a52bd5420adf1bf9bd0e1191 100644 (file)
@@ -2,10 +2,10 @@ error[E0506]: cannot assign to `*refr` because it is borrowed
   --> $DIR/issue-40288.rs:16:5
    |
 LL |     save_ref(&*refr, &mut out);
-   |              ------ borrow of `*refr` occurs here
+   |              ------ `*refr` is borrowed here
 ...
 LL |     *refr = 3;
-   |     ^^^^^^^^^ assignment to borrowed `*refr` occurs here
+   |     ^^^^^^^^^ `*refr` is assigned to here but it was already borrowed
 ...
 LL |     println!("{:?}", out[0]);
    |                      ------ borrow later used here
index 30c69f19658c84e0240bdc95a22938fd7a16133b..474313398e2bc35092cb0b5d4f5f5c5fbb395d27 100644 (file)
@@ -2,7 +2,7 @@ error[E0503]: cannot use `*y.pointer` because it was mutably borrowed
   --> $DIR/issue-45697-1.rs:20:9
    |
 LL |         let z = copy_borrowed_ptr(&mut y);
-   |                                   ------ borrow of `y` occurs here
+   |                                   ------ `y` is borrowed here
 LL |         *y.pointer += 1;
    |         ^^^^^^^^^^^^^^^ use of borrowed `y`
 ...
@@ -13,9 +13,9 @@ error[E0506]: cannot assign to `*y.pointer` because it is borrowed
   --> $DIR/issue-45697-1.rs:20:9
    |
 LL |         let z = copy_borrowed_ptr(&mut y);
-   |                                   ------ borrow of `*y.pointer` occurs here
+   |                                   ------ `*y.pointer` is borrowed here
 LL |         *y.pointer += 1;
-   |         ^^^^^^^^^^^^^^^ assignment to borrowed `*y.pointer` occurs here
+   |         ^^^^^^^^^^^^^^^ `*y.pointer` is assigned to here but it was already borrowed
 ...
 LL |         *z.pointer += 1;
    |         --------------- borrow later used here
index 26749d36f0b7b69495db9ca915c2068788f1c65f..7986fd5c9df2e0b85bf8ea00d2091ec5303ba173 100644 (file)
@@ -2,7 +2,7 @@ error[E0503]: cannot use `*y.pointer` because it was mutably borrowed
   --> $DIR/issue-45697.rs:20:9
    |
 LL |         let z = copy_borrowed_ptr(&mut y);
-   |                                   ------ borrow of `y` occurs here
+   |                                   ------ `y` is borrowed here
 LL |         *y.pointer += 1;
    |         ^^^^^^^^^^^^^^^ use of borrowed `y`
 ...
@@ -13,9 +13,9 @@ error[E0506]: cannot assign to `*y.pointer` because it is borrowed
   --> $DIR/issue-45697.rs:20:9
    |
 LL |         let z = copy_borrowed_ptr(&mut y);
-   |                                   ------ borrow of `*y.pointer` occurs here
+   |                                   ------ `*y.pointer` is borrowed here
 LL |         *y.pointer += 1;
-   |         ^^^^^^^^^^^^^^^ assignment to borrowed `*y.pointer` occurs here
+   |         ^^^^^^^^^^^^^^^ `*y.pointer` is assigned to here but it was already borrowed
 ...
 LL |         *z.pointer += 1;
    |         --------------- borrow later used here
index b09f31729a5fdcc366e694af63094c94b9bac1c5..2ae6e709d5ad5c5235584fdfd4bb086bfb098834 100644 (file)
@@ -1,11 +1,10 @@
 error[E0597]: `z` does not live long enough
   --> $DIR/issue-46471-1.rs:4:9
    |
+LL |         let mut z = 0;
+   |             ----- binding `z` declared here
 LL |         &mut z
-   |         ^^^^^^
-   |         |
-   |         borrowed value does not live long enough
-   |         borrow later used here
+   |         ^^^^^^ borrowed value does not live long enough
 LL |     };
    |     - `z` dropped here while still borrowed
 
index d450675776268221c33639a0501498cbbe1015ea..2d3b48832c527c83f1c878d47636ac4f887b3da7 100644 (file)
@@ -1,6 +1,8 @@
 error[E0597]: `line` does not live long enough
   --> $DIR/issue-52126-assign-op-invariance.rs:34:28
    |
+LL |     for line in vec!["123456789".to_string(), "12345678".to_string()] {
+   |         ---- binding `line` declared here
 LL |         let v: Vec<&str> = line.split_whitespace().collect();
    |                            ^^^^^^^^^^^^^^^^^^^^^^^ borrowed value does not live long enough
 ...
index 5dc8c2b607e61f4cf0129383c051fd491fc67b65..aee73380f15e720130131d191fed3fe7be026a8c 100644 (file)
@@ -5,6 +5,7 @@ LL | static boxed: Box<RefCell<isize>> = Box::new(RefCell::new(0));
    |               ^^^^^^^^^^^^^^^^^^^ `RefCell<isize>` cannot be shared between threads safely
    |
    = help: the trait `Sync` is not implemented for `RefCell<isize>`
+   = note: if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` instead
    = note: required for `Unique<RefCell<isize>>` to implement `Sync`
    = note: required because it appears within the type `Box<RefCell<isize>>`
    = note: shared static variables must have a type that implements `Sync`
diff --git a/tests/ui/let-else/accidental-if.rs b/tests/ui/let-else/accidental-if.rs
new file mode 100644 (file)
index 0000000..3fba630
--- /dev/null
@@ -0,0 +1,6 @@
+fn main() {
+    let x = Some(123);
+    if let Some(y) = x else { //~ ERROR this `if` expression is missing a block
+        return;
+    };
+}
diff --git a/tests/ui/let-else/accidental-if.stderr b/tests/ui/let-else/accidental-if.stderr
new file mode 100644 (file)
index 0000000..5474a67
--- /dev/null
@@ -0,0 +1,19 @@
+error: this `if` expression is missing a block after the condition
+  --> $DIR/accidental-if.rs:3:5
+   |
+LL |     if let Some(y) = x else {
+   |     ^^
+   |
+help: add a block here
+  --> $DIR/accidental-if.rs:3:23
+   |
+LL |     if let Some(y) = x else {
+   |                       ^
+help: remove the `if` if you meant to write a `let...else` statement
+  --> $DIR/accidental-if.rs:3:5
+   |
+LL |     if let Some(y) = x else {
+   |     ^^
+
+error: aborting due to previous error
+
diff --git a/tests/ui/lifetimes/issue-103582-hint-for-missing-lifetime-bound-on-trait-object-using-type-alias.fixed b/tests/ui/lifetimes/issue-103582-hint-for-missing-lifetime-bound-on-trait-object-using-type-alias.fixed
new file mode 100644 (file)
index 0000000..aa3bce2
--- /dev/null
@@ -0,0 +1,45 @@
+// run-rustfix
+
+trait Greeter0 {
+    fn greet(&self);
+}
+
+trait Greeter1 {
+    fn greet(&self);
+}
+
+type BoxedGreeter<'a> = (Box<dyn Greeter0 + 'a>, Box<dyn Greeter1 + 'a>);
+//~^ HELP to declare that the trait object captures data from argument `self`, you can add a lifetime parameter `'a` in the type alias
+
+struct FixedGreeter<'a>(pub &'a str);
+
+impl Greeter0 for FixedGreeter<'_> {
+    fn greet(&self) {
+        println!("0 {}", self.0)
+    }
+}
+
+impl Greeter1 for FixedGreeter<'_> {
+    fn greet(&self) {
+        println!("1 {}", self.0)
+    }
+}
+
+struct Greetings(pub Vec<String>);
+
+impl Greetings {
+    pub fn get(&self, i: usize) -> BoxedGreeter {
+        (Box::new(FixedGreeter(&self.0[i])), Box::new(FixedGreeter(&self.0[i])))
+        //~^ ERROR lifetime may not live long enough
+    }
+}
+
+fn main() {
+    let mut g = Greetings {0 : vec!()};
+    g.0.push("a".to_string());
+    g.0.push("b".to_string());
+    g.get(0).0.greet();
+    g.get(0).1.greet();
+    g.get(1).0.greet();
+    g.get(1).1.greet();
+}
diff --git a/tests/ui/lifetimes/issue-103582-hint-for-missing-lifetime-bound-on-trait-object-using-type-alias.rs b/tests/ui/lifetimes/issue-103582-hint-for-missing-lifetime-bound-on-trait-object-using-type-alias.rs
new file mode 100644 (file)
index 0000000..20c88ec
--- /dev/null
@@ -0,0 +1,45 @@
+// run-rustfix
+
+trait Greeter0 {
+    fn greet(&self);
+}
+
+trait Greeter1 {
+    fn greet(&self);
+}
+
+type BoxedGreeter = (Box<dyn Greeter0>, Box<dyn Greeter1>);
+//~^ HELP to declare that the trait object captures data from argument `self`, you can add a lifetime parameter `'a` in the type alias
+
+struct FixedGreeter<'a>(pub &'a str);
+
+impl Greeter0 for FixedGreeter<'_> {
+    fn greet(&self) {
+        println!("0 {}", self.0)
+    }
+}
+
+impl Greeter1 for FixedGreeter<'_> {
+    fn greet(&self) {
+        println!("1 {}", self.0)
+    }
+}
+
+struct Greetings(pub Vec<String>);
+
+impl Greetings {
+    pub fn get(&self, i: usize) -> BoxedGreeter {
+        (Box::new(FixedGreeter(&self.0[i])), Box::new(FixedGreeter(&self.0[i])))
+        //~^ ERROR lifetime may not live long enough
+    }
+}
+
+fn main() {
+    let mut g = Greetings {0 : vec!()};
+    g.0.push("a".to_string());
+    g.0.push("b".to_string());
+    g.get(0).0.greet();
+    g.get(0).1.greet();
+    g.get(1).0.greet();
+    g.get(1).1.greet();
+}
diff --git a/tests/ui/lifetimes/issue-103582-hint-for-missing-lifetime-bound-on-trait-object-using-type-alias.stderr b/tests/ui/lifetimes/issue-103582-hint-for-missing-lifetime-bound-on-trait-object-using-type-alias.stderr
new file mode 100644 (file)
index 0000000..808d8bb
--- /dev/null
@@ -0,0 +1,15 @@
+error: lifetime may not live long enough
+  --> $DIR/issue-103582-hint-for-missing-lifetime-bound-on-trait-object-using-type-alias.rs:32:9
+   |
+LL |     pub fn get(&self, i: usize) -> BoxedGreeter {
+   |                - let's call the lifetime of this reference `'1`
+LL |         (Box::new(FixedGreeter(&self.0[i])), Box::new(FixedGreeter(&self.0[i])))
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ returning this value requires that `'1` must outlive `'static`
+   |
+help: to declare that the trait object captures data from argument `self`, you can add a lifetime parameter `'a` in the type alias
+   |
+LL | type BoxedGreeter<'a> = (Box<dyn Greeter0 + 'a>, Box<dyn Greeter1 + 'a>);
+   |                  ++++                     ++++                    ++++
+
+error: aborting due to previous error
+
index 99e1e7217b45ce2318f07df0f0c37689a9858450..3602de8dd9577079f2bb7b6f5e2e9c2dfd9ad769 100644 (file)
@@ -1,6 +1,8 @@
 error[E0597]: `foo` does not live long enough
   --> $DIR/issue-90600-expected-return-static-indirect.rs:7:32
    |
+LL | fn inner(mut foo: &[u8]) {
+   |          ------- binding `foo` declared here
 LL |     let refcell = RefCell::new(&mut foo);
    |                                ^^^^^^^^ borrowed value does not live long enough
 LL |
index 287cd7d67044eb824eba79c53b7c89130d356c27..520b2ce50526f9044cd5e720c270038beb453a86 100644 (file)
@@ -1,6 +1,8 @@
 error[E0597]: `mutex` does not live long enough
   --> $DIR/format-args-temporaries-in-write.rs:41:27
    |
+LL |         let mutex = Mutex;
+   |             ----- binding `mutex` declared here
 LL |         write!(Out, "{}", mutex.lock()) /* no semicolon */
    |                           ^^^^^^^^^^^^
    |                           |
@@ -16,6 +18,8 @@ LL |     };
 error[E0597]: `mutex` does not live long enough
   --> $DIR/format-args-temporaries-in-write.rs:47:29
    |
+LL |         let mutex = Mutex;
+   |             ----- binding `mutex` declared here
 LL |         writeln!(Out, "{}", mutex.lock()) /* no semicolon */
    |                             ^^^^^^^^^^^^
    |                             |
index 90f858f80e6b5ffe340dcf0aa222b962d56b32e1..ad97f7a4a7540d08bc99643e5bb17f99d721d37b 100644 (file)
@@ -25,8 +25,8 @@ fn arbitrary_consuming_method_for_demonstration_purposes() {
 
 
                 {
-                    ::std::rt::panic_fmt(::core::fmt::Arguments::new_v1(&["Assertion failed: elem as usize\nWith captures:\n  elem = ",
-                                        "\n"], &[::core::fmt::ArgumentV1::new_debug(&__capture0)]))
+                    ::std::rt::panic_fmt(format_args!("Assertion failed: elem as usize\nWith captures:\n  elem = {0:?}\n",
+                            __capture0))
                 }
             }
     };
@@ -41,8 +41,8 @@ fn addr_of() {
         if ::core::intrinsics::unlikely(!&*__local_bind0) {
                 (&::core::asserting::Wrapper(__local_bind0)).try_capture(&mut __capture0);
                 {
-                    ::std::rt::panic_fmt(::core::fmt::Arguments::new_v1(&["Assertion failed: &elem\nWith captures:\n  elem = ",
-                                        "\n"], &[::core::fmt::ArgumentV1::new_debug(&__capture0)]))
+                    ::std::rt::panic_fmt(format_args!("Assertion failed: &elem\nWith captures:\n  elem = {0:?}\n",
+                            __capture0))
                 }
             }
     };
@@ -57,8 +57,8 @@ fn binary() {
         if ::core::intrinsics::unlikely(!(*__local_bind0 == 1)) {
                 (&::core::asserting::Wrapper(__local_bind0)).try_capture(&mut __capture0);
                 {
-                    ::std::rt::panic_fmt(::core::fmt::Arguments::new_v1(&["Assertion failed: elem == 1\nWith captures:\n  elem = ",
-                                        "\n"], &[::core::fmt::ArgumentV1::new_debug(&__capture0)]))
+                    ::std::rt::panic_fmt(format_args!("Assertion failed: elem == 1\nWith captures:\n  elem = {0:?}\n",
+                            __capture0))
                 }
             }
     };
@@ -70,8 +70,8 @@ fn binary() {
         if ::core::intrinsics::unlikely(!(*__local_bind0 >= 1)) {
                 (&::core::asserting::Wrapper(__local_bind0)).try_capture(&mut __capture0);
                 {
-                    ::std::rt::panic_fmt(::core::fmt::Arguments::new_v1(&["Assertion failed: elem >= 1\nWith captures:\n  elem = ",
-                                        "\n"], &[::core::fmt::ArgumentV1::new_debug(&__capture0)]))
+                    ::std::rt::panic_fmt(format_args!("Assertion failed: elem >= 1\nWith captures:\n  elem = {0:?}\n",
+                            __capture0))
                 }
             }
     };
@@ -83,8 +83,8 @@ fn binary() {
         if ::core::intrinsics::unlikely(!(*__local_bind0 > 0)) {
                 (&::core::asserting::Wrapper(__local_bind0)).try_capture(&mut __capture0);
                 {
-                    ::std::rt::panic_fmt(::core::fmt::Arguments::new_v1(&["Assertion failed: elem > 0\nWith captures:\n  elem = ",
-                                        "\n"], &[::core::fmt::ArgumentV1::new_debug(&__capture0)]))
+                    ::std::rt::panic_fmt(format_args!("Assertion failed: elem > 0\nWith captures:\n  elem = {0:?}\n",
+                            __capture0))
                 }
             }
     };
@@ -96,8 +96,8 @@ fn binary() {
         if ::core::intrinsics::unlikely(!(*__local_bind0 < 3)) {
                 (&::core::asserting::Wrapper(__local_bind0)).try_capture(&mut __capture0);
                 {
-                    ::std::rt::panic_fmt(::core::fmt::Arguments::new_v1(&["Assertion failed: elem < 3\nWith captures:\n  elem = ",
-                                        "\n"], &[::core::fmt::ArgumentV1::new_debug(&__capture0)]))
+                    ::std::rt::panic_fmt(format_args!("Assertion failed: elem < 3\nWith captures:\n  elem = {0:?}\n",
+                            __capture0))
                 }
             }
     };
@@ -109,8 +109,8 @@ fn binary() {
         if ::core::intrinsics::unlikely(!(*__local_bind0 <= 3)) {
                 (&::core::asserting::Wrapper(__local_bind0)).try_capture(&mut __capture0);
                 {
-                    ::std::rt::panic_fmt(::core::fmt::Arguments::new_v1(&["Assertion failed: elem <= 3\nWith captures:\n  elem = ",
-                                        "\n"], &[::core::fmt::ArgumentV1::new_debug(&__capture0)]))
+                    ::std::rt::panic_fmt(format_args!("Assertion failed: elem <= 3\nWith captures:\n  elem = {0:?}\n",
+                            __capture0))
                 }
             }
     };
@@ -122,8 +122,8 @@ fn binary() {
         if ::core::intrinsics::unlikely(!(*__local_bind0 != 3)) {
                 (&::core::asserting::Wrapper(__local_bind0)).try_capture(&mut __capture0);
                 {
-                    ::std::rt::panic_fmt(::core::fmt::Arguments::new_v1(&["Assertion failed: elem != 3\nWith captures:\n  elem = ",
-                                        "\n"], &[::core::fmt::ArgumentV1::new_debug(&__capture0)]))
+                    ::std::rt::panic_fmt(format_args!("Assertion failed: elem != 3\nWith captures:\n  elem = {0:?}\n",
+                            __capture0))
                 }
             }
     };
@@ -138,8 +138,8 @@ fn unary() {
         if ::core::intrinsics::unlikely(!**__local_bind0) {
                 (&::core::asserting::Wrapper(__local_bind0)).try_capture(&mut __capture0);
                 {
-                    ::std::rt::panic_fmt(::core::fmt::Arguments::new_v1(&["Assertion failed: *elem\nWith captures:\n  elem = ",
-                                        "\n"], &[::core::fmt::ArgumentV1::new_debug(&__capture0)]))
+                    ::std::rt::panic_fmt(format_args!("Assertion failed: *elem\nWith captures:\n  elem = {0:?}\n",
+                            __capture0))
                 }
             }
     };
index 59c091e44eb87efa0e16a1111eab535d3618a5e9..0b3425f2b1a1cec9ffa14bf5c5a606d3cb9bf5ed 100644 (file)
@@ -4,6 +4,7 @@ error[E0597]: `arg` does not live long enough
 LL |     let _arg = match args.next() {
    |         ---- borrow later stored here
 LL |         Some(arg) => {
+   |              --- binding `arg` declared here
 LL |             match arg.to_str() {
    |                   ^^^^^^^^^^^^ borrowed value does not live long enough
 ...
index 7f69e5dcfb784db1ea80cf0b567fe483007f5bc6..91d237b1d1a9085273d9778e9850ecc101c5423c 100644 (file)
@@ -75,6 +75,8 @@ LL |     fn use_pin_box_self(self: Pin<Box<Self>>) {}
 error[E0505]: cannot move out of `mut_foo` because it is borrowed
   --> $DIR/move-fn-self-receiver.rs:50:5
    |
+LL |     let mut mut_foo = Foo;
+   |         ----------- binding `mut_foo` declared here
 LL |     let ret = mut_foo.use_mut_self();
    |               ---------------------- borrow of `mut_foo` occurs here
 LL |     mut_foo;
index 6583546aa5c1fe70bbecdb12f294372a20dcdd7c..5f2074edb12407bf0ab8b4b128cf48846a4f75f2 100644 (file)
@@ -13,9 +13,9 @@ error[E0506]: cannot assign to `*foo` because it is borrowed
   --> $DIR/mut-pattern-internal-mutability.rs:13:5
    |
 LL |     let &mut ref x = foo;
-   |              ----- borrow of `*foo` occurs here
+   |              ----- `*foo` is borrowed here
 LL |     *foo += 1;
-   |     ^^^^^^^^^ assignment to borrowed `*foo` occurs here
+   |     ^^^^^^^^^ `*foo` is assigned to here but it was already borrowed
 LL |     drop(x);
    |          - borrow later used here
 
diff --git a/tests/ui/mutexguard-sync.rs b/tests/ui/mutexguard-sync.rs
deleted file mode 100644 (file)
index b564183..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-// MutexGuard<Cell<i32>> must not be Sync, that would be unsound.
-use std::sync::Mutex;
-use std::cell::Cell;
-
-fn test_sync<T: Sync>(_t: T) {}
-
-fn main()
-{
-    let m = Mutex::new(Cell::new(0i32));
-    let guard = m.lock().unwrap();
-    test_sync(guard);
-    //~^ ERROR `Cell<i32>` cannot be shared between threads safely [E0277]
-}
diff --git a/tests/ui/mutexguard-sync.stderr b/tests/ui/mutexguard-sync.stderr
deleted file mode 100644 (file)
index 3fbb2dd..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-error[E0277]: `Cell<i32>` cannot be shared between threads safely
-  --> $DIR/mutexguard-sync.rs:11:15
-   |
-LL |     test_sync(guard);
-   |     --------- ^^^^^ `Cell<i32>` cannot be shared between threads safely
-   |     |
-   |     required by a bound introduced by this call
-   |
-   = help: the trait `Sync` is not implemented for `Cell<i32>`
-   = note: required for `MutexGuard<'_, Cell<i32>>` to implement `Sync`
-note: required by a bound in `test_sync`
-  --> $DIR/mutexguard-sync.rs:5:17
-   |
-LL | fn test_sync<T: Sync>(_t: T) {}
-   |                 ^^^^ required by this bound in `test_sync`
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0277`.
index d629caa435319c355347a94dabec6360edff860e..1cca4077d825ac1bbc163ad71ac88944cb041f37 100644 (file)
@@ -4,6 +4,7 @@ error[E0597]: `v` does not live long enough
 LL |     let x = gimme({
    |             ----- borrow later used by call
 LL |         let v = (22,);
+   |             - binding `v` declared here
 LL |         &v
    |         ^^ borrowed value does not live long enough
 LL |
index 9d4682667dddddbfcf9032509fab39eed1badccf..33e3eb797969e36f92e62f9615ebe111e503ea61 100644 (file)
@@ -2,7 +2,7 @@ error[E0503]: cannot use `e` because it was mutably borrowed
   --> $DIR/borrowed-match-issue-45045.rs:12:11
    |
 LL |     let f = &mut e;
-   |             ------ borrow of `e` occurs here
+   |             ------ `e` is borrowed here
 LL |     let g = f;
 LL |     match e {
    |           ^ use of borrowed `e`
index cdfe7f6db82a929eb29c4c6f1f7e608aaa4b7004..84b7ecf2f7da82c3e3e8cc10d058b17c981742a2 100644 (file)
@@ -1,6 +1,9 @@
 error[E0597]: `y` does not live long enough
   --> $DIR/capture-ref-in-struct.rs:18:16
    |
+LL |         let y = 22;
+   |             - binding `y` declared here
+...
 LL |             y: &y,
    |                ^^ borrowed value does not live long enough
 ...
index 0a09353b8ec0a52f941f11331dd54b180b04e1e7..035dd5a561096cbaef671a20e200204ca6a0b1b0 100644 (file)
@@ -38,7 +38,7 @@ error[E0503]: cannot use `x` because it was mutably borrowed
   --> $DIR/closure-access-spans.rs:23:13
    |
 LL |     let r = &mut x;
-   |             ------ borrow of `x` occurs here
+   |             ------ `x` is borrowed here
 LL |     move || x;
    |             ^ use of borrowed `x`
 LL |     r.use_ref();
@@ -47,6 +47,8 @@ LL |     r.use_ref();
 error[E0505]: cannot move out of `x` because it is borrowed
   --> $DIR/closure-access-spans.rs:29:5
    |
+LL | fn closure_move_capture_conflict(mut x: String) {
+   |                                  ----- binding `x` declared here
 LL |     let r = &x;
    |             -- borrow of `x` occurs here
 LL |     || x;
index bada4e1b84b52cdf25e9222f62022d9bdadd15b9..cf0df5834cc0dd39e30115455d5395c38ccf8df0 100644 (file)
@@ -40,9 +40,9 @@ error[E0506]: cannot assign to `x` because it is borrowed
 LL |     let f = || x;
    |             -- - borrow occurs due to use in closure
    |             |
-   |             borrow of `x` occurs here
+   |             `x` is borrowed here
 LL |     x = 1;
-   |     ^^^^^ assignment to borrowed `x` occurs here
+   |     ^^^^^ `x` is assigned to here but it was already borrowed
 LL |     f.use_ref();
    |     ----------- borrow later used here
 
@@ -52,7 +52,7 @@ error[E0503]: cannot use `x` because it was mutably borrowed
 LL |     let f = || x = 0;
    |             -- - borrow occurs due to use of `x` in closure
    |             |
-   |             borrow of `x` occurs here
+   |             `x` is borrowed here
 LL |     let y = x;
    |             ^ use of borrowed `x`
 LL |     f.use_ref();
@@ -100,9 +100,9 @@ error[E0506]: cannot assign to `x` because it is borrowed
 LL |     let f = || x = 0;
    |             -- - borrow occurs due to use in closure
    |             |
-   |             borrow of `x` occurs here
+   |             `x` is borrowed here
 LL |     x = 1;
-   |     ^^^^^ assignment to borrowed `x` occurs here
+   |     ^^^^^ `x` is assigned to here but it was already borrowed
 LL |     f.use_ref();
    |     ----------- borrow later used here
 
@@ -160,9 +160,9 @@ error[E0506]: cannot assign to `*x` because it is borrowed
 LL |     let f = || *x = 0;
    |             -- -- borrow occurs due to use in closure
    |             |
-   |             borrow of `*x` occurs here
+   |             `*x` is borrowed here
 LL |     *x = 1;
-   |     ^^^^^^ assignment to borrowed `*x` occurs here
+   |     ^^^^^^ `*x` is assigned to here but it was already borrowed
 LL |     f.use_ref();
    |     ----------- borrow later used here
 
index f67c312b946883a486655688f21717605e098567..5a8462d4dc56e4e1279c9092a9831d5fafbd839f 100644 (file)
@@ -21,6 +21,9 @@ LL | fn test() {
 error[E0597]: `y` does not live long enough
   --> $DIR/escape-argument.rs:27:25
    |
+LL |         let y = 22;
+   |             - binding `y` declared here
+LL |         let mut closure = expect_sig(|p, y| *p = y);
 LL |         closure(&mut p, &y);
    |                         ^^ borrowed value does not live long enough
 LL |
index 7991abeb7a800d72a6e04c0e4ef402911420492c..721cd45ded98e2866c4e6a838ca67e80448f8c16 100644 (file)
@@ -53,6 +53,8 @@ LL | fn case2() {
 error[E0597]: `a` does not live long enough
   --> $DIR/propagate-approximated-shorter-to-static-comparing-against-free.rs:30:26
    |
+LL |       let a = 0;
+   |           - binding `a` declared here
 LL |       let cell = Cell::new(&a);
    |                            ^^ borrowed value does not live long enough
 ...
index ad928f1bbc984373031b9be3ebaec01b64d027d3..0e27e5f5f7c162adf7d46e8cbabf54af423edcdc 100644 (file)
@@ -2,9 +2,9 @@ error[E0506]: cannot assign to `x` because it is borrowed
   --> $DIR/closure-use-spans.rs:5:5
    |
 LL |     let y = &x;
-   |             -- borrow of `x` occurs here
+   |             -- `x` is borrowed here
 LL |     x = 0;
-   |     ^^^^^ assignment to borrowed `x` occurs here
+   |     ^^^^^ `x` is assigned to here but it was already borrowed
 LL |     || *y;
    |        -- borrow later captured here by closure
 
@@ -12,9 +12,9 @@ error[E0506]: cannot assign to `x` because it is borrowed
   --> $DIR/closure-use-spans.rs:11:5
    |
 LL |     let y = &mut x;
-   |             ------ borrow of `x` occurs here
+   |             ------ `x` is borrowed here
 LL |     x = 0;
-   |     ^^^^^ assignment to borrowed `x` occurs here
+   |     ^^^^^ `x` is assigned to here but it was already borrowed
 LL |     || *y = 1;
    |        -- borrow later captured here by closure
 
@@ -22,9 +22,9 @@ error[E0506]: cannot assign to `x` because it is borrowed
   --> $DIR/closure-use-spans.rs:17:5
    |
 LL |     let y = &x;
-   |             -- borrow of `x` occurs here
+   |             -- `x` is borrowed here
 LL |     x = 0;
-   |     ^^^^^ assignment to borrowed `x` occurs here
+   |     ^^^^^ `x` is assigned to here but it was already borrowed
 LL |     move || *y;
    |             -- borrow later captured here by closure
 
index 65be3b37e0e3bed31239ba5bc20258d2b006527a..862c925b468fd3a5e12da81bb73881dda35a6407 100644 (file)
@@ -1,6 +1,8 @@
 error[E0597]: `s` does not live long enough
   --> $DIR/do-not-ignore-lifetime-bounds-in-copy-proj.rs:9:18
    |
+LL |     let s = 2;
+   |         - binding `s` declared here
 LL |     let a = (Foo(&s),);
    |                  ^^ borrowed value does not live long enough
 LL |     drop(a.0);
index b811ba4fd0cd2a4c12456083ecd99e1b03efd004..ebaf6d1244d7d6c12cc02e3917e86e19196b8123 100644 (file)
@@ -1,6 +1,8 @@
 error[E0597]: `s` does not live long enough
   --> $DIR/do-not-ignore-lifetime-bounds-in-copy.rs:8:17
    |
+LL |     let s = 2;
+   |         - binding `s` declared here
 LL |     let a = Foo(&s);
    |                 ^^ borrowed value does not live long enough
 LL |     drop(a);
index fad6121cbca52f4da0e2c0031dea932e322e78ea..289b246e663e1a705bf7a2f0fd8278f29fa2bb52 100644 (file)
@@ -10,6 +10,7 @@ error[E0597]: `y` does not live long enough
 LL |     for ref mut d in v {
    |                      - a temporary with access to the borrow is created here ...
 LL |         let y = ();
+   |             - binding `y` declared here
 LL |         *d = D(&y);
    |                ^^ borrowed value does not live long enough
 LL |     }
index cb280880950043fa07ee9427c7a4ffddfeb5461f..0ddb7adbb38223dffa6cdbbaa1df5b95024aeabd 100644 (file)
@@ -2,10 +2,10 @@ error[E0506]: cannot assign to `v[_]` because it is borrowed
   --> $DIR/drop-no-may-dangle.rs:18:9
    |
 LL |     let p: WrapMayNotDangle<&usize> = WrapMayNotDangle { value: &v[0] };
-   |                                                                 ----- borrow of `v[_]` occurs here
+   |                                                                 ----- `v[_]` is borrowed here
 ...
 LL |         v[0] += 1;
-   |         ^^^^^^^^^ assignment to borrowed `v[_]` occurs here
+   |         ^^^^^^^^^ `v[_]` is assigned to here but it was already borrowed
 ...
 LL | }
    | - borrow might be used here, when `p` is dropped and runs the `Drop` code for type `WrapMayNotDangle`
@@ -14,10 +14,10 @@ error[E0506]: cannot assign to `v[_]` because it is borrowed
   --> $DIR/drop-no-may-dangle.rs:21:5
    |
 LL |     let p: WrapMayNotDangle<&usize> = WrapMayNotDangle { value: &v[0] };
-   |                                                                 ----- borrow of `v[_]` occurs here
+   |                                                                 ----- `v[_]` is borrowed here
 ...
 LL |     v[0] += 1;
-   |     ^^^^^^^^^ assignment to borrowed `v[_]` occurs here
+   |     ^^^^^^^^^ `v[_]` is assigned to here but it was already borrowed
 LL | }
    | - borrow might be used here, when `p` is dropped and runs the `Drop` code for type `WrapMayNotDangle`
 
index 8854dd8d68c9daa460beb8f50b83da3be37f30c1..7edc3dcc5cde3e03653955c7a71d2f4942785630 100644 (file)
@@ -2,10 +2,10 @@ error[E0506]: cannot assign to `*s` because it is borrowed
   --> $DIR/guarantor-issue-46974.rs:7:5
    |
 LL |     let t = &mut *s; // this borrow should last for the entire function
-   |             ------- borrow of `*s` occurs here
+   |             ------- `*s` is borrowed here
 LL |     let x = &t.0;
 LL |     *s = (2,);
-   |     ^^^^^^^^^ assignment to borrowed `*s` occurs here
+   |     ^^^^^^^^^ `*s` is assigned to here but it was already borrowed
 LL |     *x
    |     -- borrow later used here
 
index 45119018d4e60570243a455dc0129f584db68403..4a512560c87519160e3c4572e9b573bc3bcc062a 100644 (file)
@@ -4,7 +4,7 @@ error[E0507]: cannot move out of `foo` in pattern guard
 LL |             if { (|| { let bar = foo; bar.take() })(); false } => {},
    |                   ^^             --- move occurs because `foo` has type `&mut Option<&i32>`, which does not implement the `Copy` trait
    |                   |
-   |                   move out of `foo` occurs here
+   |                   `foo` is moved here
    |
    = note: variables bound in patterns cannot be moved from until after the end of the pattern guard
 
@@ -14,7 +14,7 @@ error[E0507]: cannot move out of `foo` in pattern guard
 LL |             if let Some(()) = { (|| { let bar = foo; bar.take() })(); None } => {},
    |                                  ^^             --- move occurs because `foo` has type `&mut Option<&i32>`, which does not implement the `Copy` trait
    |                                  |
-   |                                  move out of `foo` occurs here
+   |                                  `foo` is moved here
    |
    = note: variables bound in patterns cannot be moved from until after the end of the pattern guard
 
index 1ba696593afffe4adafbac72bb0e1055fa4b4d71..0b5d723172c76601c0948a0c5977412610d1ec2f 100644 (file)
@@ -4,7 +4,7 @@ error[E0507]: cannot move out of `foo` in pattern guard
 LL |                 (|| { let bar = foo; bar.take() })();
    |                  ^^             --- move occurs because `foo` has type `&mut Option<&i32>`, which does not implement the `Copy` trait
    |                  |
-   |                  move out of `foo` occurs here
+   |                  `foo` is moved here
    |
    = note: variables bound in patterns cannot be moved from until after the end of the pattern guard
 
@@ -14,7 +14,7 @@ error[E0507]: cannot move out of `foo` in pattern guard
 LL |                 (|| { let bar = foo; bar.take() })();
    |                  ^^             --- move occurs because `foo` has type `&mut Option<&i32>`, which does not implement the `Copy` trait
    |                  |
-   |                  move out of `foo` occurs here
+   |                  `foo` is moved here
    |
    = note: variables bound in patterns cannot be moved from until after the end of the pattern guard
 
index e0b3b5494d0a574b53f2d1fa035277500359dcc2..204eda3d2679631ccb93b6505769f2c727b5ba73 100644 (file)
@@ -4,10 +4,10 @@ error[E0506]: cannot assign to `vecvec` because it is borrowed
 LL |       vecvec[0] += {
    |       ------
    |       |
-   |  _____borrow of `vecvec` occurs here
+   |  _____`vecvec` is borrowed here
    | |
 LL | |         vecvec = vec![];
-   | |         ^^^^^^ assignment to borrowed `vecvec` occurs here
+   | |         ^^^^^^ `vecvec` is assigned to here but it was already borrowed
 LL | |
 LL | |         0
 LL | |     };
index e6e95ee613647a1cff34d4d4479a73ab32e75162..f337e23455070ba8ec0962364e6b424e473c9728 100644 (file)
@@ -1,6 +1,8 @@
 error[E0597]: `a` does not live long enough
   --> $DIR/issue-46036.rs:8:24
    |
+LL |     let a = 3;
+   |         - binding `a` declared here
 LL |     let foo = Foo { x: &a };
    |                        ^^
    |                        |
index 2f94039c0c3a934af7970fa24cc473ce8f4e8c8f..e24606e0b53e866b0f4488d6e3aa65778e793d70 100644 (file)
@@ -2,10 +2,10 @@ error[E0506]: cannot assign to `x` because it is borrowed
   --> $DIR/issue-48803.rs:10:5
    |
 LL |     let y = &x;
-   |             -- borrow of `x` occurs here
+   |             -- `x` is borrowed here
 ...
 LL |     x = "modified";
-   |     ^^^^^^^^^^^^^^ assignment to borrowed `x` occurs here
+   |     ^^^^^^^^^^^^^^ `x` is assigned to here but it was already borrowed
 LL |
 LL |     println!("{}", w); // prints "modified"
    |                    - borrow later used here
index ac385e056b9f81712c7e58248950222e04f9d72a..35d39bb6e908d7110db644eec628c44d10c10c07 100644 (file)
@@ -1,6 +1,8 @@
 error[E0597]: `x` does not live long enough
   --> $DIR/issue-52534-2.rs:6:13
    |
+LL |         let x = 32;
+   |             - binding `x` declared here
 LL |         y = &x
    |             ^^ borrowed value does not live long enough
 LL |
index 5cedea6e66520a5e022ce895232324b31bb79272..338f64841321f70dc5fd23285805a02f0f5877c5 100644 (file)
@@ -1,6 +1,8 @@
 error[E0597]: `tmp0` does not live long enough
   --> $DIR/issue-52663-trait-object.rs:12:20
    |
+LL |         let tmp0 = 3;
+   |             ---- binding `tmp0` declared here
 LL |         let tmp1 = &tmp0;
    |                    ^^^^^ borrowed value does not live long enough
 LL |         Box::new(tmp1) as Box<dyn Foo + '_>
index d8f43cbc92a1e7874581d6af9fa21704c9cec2be..4a32c777a86f1492b471aaaf736df2501cd9a381 100644 (file)
@@ -1,6 +1,9 @@
 error[E0597]: `_thing1` does not live long enough
   --> $DIR/issue-54382-use-span-of-tail-of-block.rs:7:29
    |
+LL |         let mut _thing1 = D(Box::new("thing1"));
+   |             ----------- binding `_thing1` declared here
+...
 LL |             D("other").next(&_thing1)
    |             ----------------^^^^^^^^-
    |             |               |
index a8e1edc5497422311da7754564e32d8c29978c78..d41d462f2bcb0130bc4f032ddf223b7d3b29bd87 100644 (file)
@@ -1,6 +1,9 @@
 error[E0597]: `counter` does not live long enough
   --> $DIR/issue-54556-niconii.rs:22:20
    |
+LL |     let counter = Mutex;
+   |         ------- binding `counter` declared here
+LL |
 LL |     if let Ok(_) = counter.lock() { }
    |                    ^^^^^^^^^^^^^^
    |                    |
index 036a7a0abfdcc7eecd3b2d9b17ac628460ca1f8a..f9e82cb003fc2be9e34722586dc22df8dfbe851c 100644 (file)
@@ -1,6 +1,8 @@
 error[E0597]: `stmt` does not live long enough
   --> $DIR/issue-54556-stephaneyfx.rs:27:21
    |
+LL |     let stmt = Statement;
+   |         ---- binding `stmt` declared here
 LL |     let rows = Rows(&stmt);
    |                     ^^^^^ borrowed value does not live long enough
 LL |     rows.map(|row| row).next()
index 92f5ffdf388ed22e724e4e53ab1df8efb8ee84ed..4eae9fdcde0d29c1ebff0a4937a714e3865bddca 100644 (file)
@@ -1,6 +1,9 @@
 error[E0597]: `_thing1` does not live long enough
   --> $DIR/issue-54556-temps-in-tail-diagnostic.rs:5:11
    |
+LL |         let mut _thing1 = D(Box::new("thing1"));
+   |             ----------- binding `_thing1` declared here
+LL |         // D("other").next(&_thing1).end()
 LL |         D(&_thing1).end()
    |         --^^^^^^^^-
    |         | |
index 25226e2967353b45a8f804d12e60e758c341ee7e..a2a7a8486545cb0b0ab8f36764f49d870af666a5 100644 (file)
@@ -2,11 +2,12 @@ error[E0597]: `_t1` does not live long enough
   --> $DIR/issue-54556-used-vs-unused-tails.rs:10:55
    |
 LL |     {              let mut _t1 = D(Box::new("t1")); D(&_t1).end()    } ; // suggest `;`
-   |                                                     --^^^^-          - - ... and the borrow might be used here, when that temporary is dropped and runs the `Drop` code for type `D`
-   |                                                     | |              |
-   |                                                     | |              `_t1` dropped here while still borrowed
-   |                                                     | borrowed value does not live long enough
-   |                                                     a temporary with access to the borrow is created here ...
+   |                        -------                      --^^^^-          - - ... and the borrow might be used here, when that temporary is dropped and runs the `Drop` code for type `D`
+   |                        |                            | |              |
+   |                        |                            | |              `_t1` dropped here while still borrowed
+   |                        |                            | borrowed value does not live long enough
+   |                        |                            a temporary with access to the borrow is created here ...
+   |                        binding `_t1` declared here
    |
 help: consider adding semicolon after the expression so its temporaries are dropped sooner, before the local variables declared by the block are dropped
    |
@@ -17,11 +18,12 @@ error[E0597]: `_t1` does not live long enough
   --> $DIR/issue-54556-used-vs-unused-tails.rs:13:55
    |
 LL |     {            { let mut _t1 = D(Box::new("t1")); D(&_t1).end() }  } ; // suggest `;`
-   |                                                     --^^^^-       -    - ... and the borrow might be used here, when that temporary is dropped and runs the `Drop` code for type `D`
-   |                                                     | |           |
-   |                                                     | |           `_t1` dropped here while still borrowed
-   |                                                     | borrowed value does not live long enough
-   |                                                     a temporary with access to the borrow is created here ...
+   |                        -------                      --^^^^-       -    - ... and the borrow might be used here, when that temporary is dropped and runs the `Drop` code for type `D`
+   |                        |                            | |           |
+   |                        |                            | |           `_t1` dropped here while still borrowed
+   |                        |                            | borrowed value does not live long enough
+   |                        |                            a temporary with access to the borrow is created here ...
+   |                        binding `_t1` declared here
    |
 help: consider adding semicolon after the expression so its temporaries are dropped sooner, before the local variables declared by the block are dropped
    |
@@ -32,11 +34,12 @@ error[E0597]: `_t1` does not live long enough
   --> $DIR/issue-54556-used-vs-unused-tails.rs:16:55
    |
 LL |     {            { let mut _t1 = D(Box::new("t1")); D(&_t1).end() }; }   // suggest `;`
-   |                                                     --^^^^-       -- ... and the borrow might be used here, when that temporary is dropped and runs the `Drop` code for type `D`
-   |                                                     | |           |
-   |                                                     | |           `_t1` dropped here while still borrowed
-   |                                                     | borrowed value does not live long enough
-   |                                                     a temporary with access to the borrow is created here ...
+   |                        -------                      --^^^^-       -- ... and the borrow might be used here, when that temporary is dropped and runs the `Drop` code for type `D`
+   |                        |                            | |           |
+   |                        |                            | |           `_t1` dropped here while still borrowed
+   |                        |                            | borrowed value does not live long enough
+   |                        |                            a temporary with access to the borrow is created here ...
+   |                        binding `_t1` declared here
    |
 help: consider adding semicolon after the expression so its temporaries are dropped sooner, before the local variables declared by the block are dropped
    |
@@ -47,11 +50,12 @@ error[E0597]: `_t1` does not live long enough
   --> $DIR/issue-54556-used-vs-unused-tails.rs:19:55
    |
 LL |     let _ =      { let mut _t1 = D(Box::new("t1")); D(&_t1).end()    } ; // suggest `;`
-   |                                                     --^^^^-          - - ... and the borrow might be used here, when that temporary is dropped and runs the `Drop` code for type `D`
-   |                                                     | |              |
-   |                                                     | |              `_t1` dropped here while still borrowed
-   |                                                     | borrowed value does not live long enough
-   |                                                     a temporary with access to the borrow is created here ...
+   |                        -------                      --^^^^-          - - ... and the borrow might be used here, when that temporary is dropped and runs the `Drop` code for type `D`
+   |                        |                            | |              |
+   |                        |                            | |              `_t1` dropped here while still borrowed
+   |                        |                            | borrowed value does not live long enough
+   |                        |                            a temporary with access to the borrow is created here ...
+   |                        binding `_t1` declared here
    |
 help: consider adding semicolon after the expression so its temporaries are dropped sooner, before the local variables declared by the block are dropped
    |
@@ -62,11 +66,12 @@ error[E0597]: `_t1` does not live long enough
   --> $DIR/issue-54556-used-vs-unused-tails.rs:22:55
    |
 LL |     let _u =     { let mut _t1 = D(Box::new("t1")); D(&_t1).unit()   } ; // suggest `;`
-   |                                                     --^^^^-          - - ... and the borrow might be used here, when that temporary is dropped and runs the `Drop` code for type `D`
-   |                                                     | |              |
-   |                                                     | |              `_t1` dropped here while still borrowed
-   |                                                     | borrowed value does not live long enough
-   |                                                     a temporary with access to the borrow is created here ...
+   |                        -------                      --^^^^-          - - ... and the borrow might be used here, when that temporary is dropped and runs the `Drop` code for type `D`
+   |                        |                            | |              |
+   |                        |                            | |              `_t1` dropped here while still borrowed
+   |                        |                            | borrowed value does not live long enough
+   |                        |                            a temporary with access to the borrow is created here ...
+   |                        binding `_t1` declared here
    |
 help: consider adding semicolon after the expression so its temporaries are dropped sooner, before the local variables declared by the block are dropped
    |
@@ -77,11 +82,12 @@ error[E0597]: `_t1` does not live long enough
   --> $DIR/issue-54556-used-vs-unused-tails.rs:25:55
    |
 LL |     let _x =     { let mut _t1 = D(Box::new("t1")); D(&_t1).end()    } ; // `let x = ...; x`
-   |                                                     --^^^^-          - - ... and the borrow might be used here, when that temporary is dropped and runs the `Drop` code for type `D`
-   |                                                     | |              |
-   |                                                     | |              `_t1` dropped here while still borrowed
-   |                                                     | borrowed value does not live long enough
-   |                                                     a temporary with access to the borrow is created here ...
+   |                        -------                      --^^^^-          - - ... and the borrow might be used here, when that temporary is dropped and runs the `Drop` code for type `D`
+   |                        |                            | |              |
+   |                        |                            | |              `_t1` dropped here while still borrowed
+   |                        |                            | borrowed value does not live long enough
+   |                        |                            a temporary with access to the borrow is created here ...
+   |                        binding `_t1` declared here
    |
    = note: the temporary is part of an expression at the end of a block;
            consider forcing this temporary to be dropped sooner, before the block's local variables are dropped
@@ -94,11 +100,12 @@ error[E0597]: `_t1` does not live long enough
   --> $DIR/issue-54556-used-vs-unused-tails.rs:30:55
    |
 LL |     _y =         { let mut _t1 = D(Box::new("t1")); D(&_t1).end() } ; // `let x = ...; x`
-   |                                                     --^^^^-       - - ... and the borrow might be used here, when that temporary is dropped and runs the `Drop` code for type `D`
-   |                                                     | |           |
-   |                                                     | |           `_t1` dropped here while still borrowed
-   |                                                     | borrowed value does not live long enough
-   |                                                     a temporary with access to the borrow is created here ...
+   |                        -------                      --^^^^-       - - ... and the borrow might be used here, when that temporary is dropped and runs the `Drop` code for type `D`
+   |                        |                            | |           |
+   |                        |                            | |           `_t1` dropped here while still borrowed
+   |                        |                            | borrowed value does not live long enough
+   |                        |                            a temporary with access to the borrow is created here ...
+   |                        binding `_t1` declared here
    |
    = note: the temporary is part of an expression at the end of a block;
            consider forcing this temporary to be dropped sooner, before the block's local variables are dropped
@@ -111,12 +118,13 @@ error[E0597]: `_t1` does not live long enough
   --> $DIR/issue-54556-used-vs-unused-tails.rs:37:55
    |
 LL | fn f_local_ref() { let mut _t1 = D(Box::new("t1")); D(&_t1).unit()   }  // suggest `;`
-   |                                                     --^^^^-          -
-   |                                                     | |              |
-   |                                                     | |              `_t1` dropped here while still borrowed
-   |                                                     | |              ... and the borrow might be used here, when that temporary is dropped and runs the `Drop` code for type `D`
-   |                                                     | borrowed value does not live long enough
-   |                                                     a temporary with access to the borrow is created here ...
+   |                        -------                      --^^^^-          -
+   |                        |                            | |              |
+   |                        |                            | |              `_t1` dropped here while still borrowed
+   |                        |                            | |              ... and the borrow might be used here, when that temporary is dropped and runs the `Drop` code for type `D`
+   |                        |                            | borrowed value does not live long enough
+   |                        |                            a temporary with access to the borrow is created here ...
+   |                        binding `_t1` declared here
    |
 help: consider adding semicolon after the expression so its temporaries are dropped sooner, before the local variables declared by the block are dropped
    |
@@ -127,12 +135,13 @@ error[E0597]: `_t1` does not live long enough
   --> $DIR/issue-54556-used-vs-unused-tails.rs:40:55
    |
 LL | fn f() -> String { let mut _t1 = D(Box::new("t1")); D(&_t1).end()   }   // `let x = ...; x`
-   |                                                     --^^^^-         -
-   |                                                     | |             |
-   |                                                     | |             `_t1` dropped here while still borrowed
-   |                                                     | |             ... and the borrow might be used here, when that temporary is dropped and runs the `Drop` code for type `D`
-   |                                                     | borrowed value does not live long enough
-   |                                                     a temporary with access to the borrow is created here ...
+   |                        -------                      --^^^^-         -
+   |                        |                            | |             |
+   |                        |                            | |             `_t1` dropped here while still borrowed
+   |                        |                            | |             ... and the borrow might be used here, when that temporary is dropped and runs the `Drop` code for type `D`
+   |                        |                            | borrowed value does not live long enough
+   |                        |                            a temporary with access to the borrow is created here ...
+   |                        binding `_t1` declared here
    |
    = note: the temporary is part of an expression at the end of a block;
            consider forcing this temporary to be dropped sooner, before the block's local variables are dropped
index 9f27fac15a7f67161922cf5b42101c3807bb7adf..adc419ae51562534b10ed164be2a58c833b4bd08 100644 (file)
@@ -2,10 +2,10 @@ error[E0506]: cannot assign to `x` because it is borrowed
   --> $DIR/issue-54556-wrap-it-up.rs:27:5
    |
 LL |     let wrap = Wrap { p: &mut x };
-   |                          ------ borrow of `x` occurs here
+   |                          ------ `x` is borrowed here
 ...
 LL |     x = 1;
-   |     ^^^^^ assignment to borrowed `x` occurs here
+   |     ^^^^^ `x` is assigned to here but it was already borrowed
 LL | }
    | - borrow might be used here, when `foo` is dropped and runs the destructor for type `Foo<'_>`
 
index bf3e58e8cdb19b1c5cfea5247b1bba8e6cc4af73..ecb9ef0aef96e3773b54b54faf9fe553f402223b 100644 (file)
@@ -1,6 +1,8 @@
 error[E0597]: `a` does not live long enough
   --> $DIR/issue-55511.rs:13:28
    |
+LL |     let a = 22;
+   |         - binding `a` declared here
 LL |     let b = Some(Cell::new(&a));
    |                            ^^ borrowed value does not live long enough
 ...
index 31f40d8252ed6a40745dc26e2606729a84cf5a8b..d5effd6f346d16bc543768676128a57ae3e33bb7 100644 (file)
@@ -13,9 +13,9 @@ error[E0506]: cannot assign to `*x` because it is borrowed
   --> $DIR/issue-57989.rs:5:5
    |
 LL |     let g = &x;
-   |             -- borrow of `*x` occurs here
+   |             -- `*x` is borrowed here
 LL |     *x = 0;
-   |     ^^^^^^ assignment to borrowed `*x` occurs here
+   |     ^^^^^^ `*x` is assigned to here but it was already borrowed
 LL |
 LL |     g;
    |     - borrow later used here
index e234ebb04e16a5ea874c7482a3cf11da6bc03dd5..851e3628748f22af1610de992fc5dd0b5523c718 100644 (file)
@@ -2,7 +2,9 @@ error[E0597]: `x` does not live long enough
   --> $DIR/issue-68550.rs:12:20
    |
 LL | fn run<'a, A>(x: A)
-   |        -- lifetime `'a` defined here
+   |        --     - binding `x` declared here
+   |        |
+   |        lifetime `'a` defined here
 ...
 LL |     let _: &'a A = &x;
    |            -----   ^^ borrowed value does not live long enough
index 5e55cb502caa9c235d696fa1760a7d94223ec94a..1b41230d7ba39976eedf542397a86725c95db886 100644 (file)
@@ -1,6 +1,9 @@
 error[E0597]: `n` does not live long enough
   --> $DIR/issue-69114-static-mut-ty.rs:19:15
    |
+LL |     let n = 42;
+   |         - binding `n` declared here
+LL |     unsafe {
 LL |         BAR = &n;
    |         ------^^
    |         |     |
@@ -13,6 +16,9 @@ LL | }
 error[E0597]: `n` does not live long enough
   --> $DIR/issue-69114-static-mut-ty.rs:27:22
    |
+LL |     let n = 42;
+   |         - binding `n` declared here
+LL |     unsafe {
 LL |         BAR_ELIDED = &n;
    |         -------------^^
    |         |            |
index 0815e74b5537d9a2bafa634329286a9aa5f7cde0..9215e850f7d8fa063cf11c5f9faf170d169cd374 100644 (file)
@@ -1,6 +1,8 @@
 error[E0597]: `n` does not live long enough
   --> $DIR/issue-69114-static-ty.rs:7:9
    |
+LL |     let n = 42;
+   |         - binding `n` declared here
 LL |     FOO(&n);
    |     ----^^-
    |     |   |
index eb8442b31d7c73b323076b65fee62c112f77bfa5..58e378ab02118d7455c6b62f0e811d782c0dd136 100644 (file)
@@ -2,10 +2,10 @@ error[E0506]: cannot assign to `data.0` because it is borrowed
   --> $DIR/loan_ends_mid_block_pair.rs:12:5
    |
 LL |     let c = &mut data.0;
-   |             ----------- borrow of `data.0` occurs here
+   |             ----------- `data.0` is borrowed here
 LL |     capitalize(c);
 LL |     data.0 = 'e';
-   |     ^^^^^^^^^^^^ assignment to borrowed `data.0` occurs here
+   |     ^^^^^^^^^^^^ `data.0` is assigned to here but it was already borrowed
 ...
 LL |     capitalize(c);
    |                - borrow later used here
index f5c10f3ddea0ea0686342e06ab87b16a6b4d63fb..a6b3328b5a294475ca720c90e10c330af78902d9 100644 (file)
@@ -1,6 +1,8 @@
 error[E0597]: `local` does not live long enough
   --> $DIR/local-outlives-static-via-hrtb.rs:24:28
    |
+LL |     let local = 0;
+   |         ----- binding `local` declared here
 LL |     assert_static_via_hrtb(&local);
    |     -----------------------^^^^^^-
    |     |                      |
@@ -19,6 +21,9 @@ LL | fn assert_static_via_hrtb<G>(_: G) where for<'a> G: Outlives<'a> {}
 error[E0597]: `local` does not live long enough
   --> $DIR/local-outlives-static-via-hrtb.rs:25:45
    |
+LL |     let local = 0;
+   |         ----- binding `local` declared here
+LL |     assert_static_via_hrtb(&local);
 LL |     assert_static_via_hrtb_with_assoc_type(&&local);
    |     ----------------------------------------^^^^^^-
    |     |                                       |
index c6d15a936d81939e13a770ae03fde1a622a9dbe1..36f2cd0b85d1c62e355dfc5b84d5a844eaa57409 100644 (file)
@@ -2,7 +2,7 @@ error[E0503]: cannot use `y.1` because it was mutably borrowed
   --> $DIR/match-cfg-fake-edges2.rs:8:5
    |
 LL |     let r = &mut y.1;
-   |             -------- borrow of `y.1` occurs here
+   |             -------- `y.1` is borrowed here
 ...
 LL |     match y {
    |     ^^^^^^^ use of borrowed `y.1`
index fa01d3a6fd1e0092a95e40c270c4f7b681626f97..afd853c403ee38d83f40315da6a4915a4d075ef4 100644 (file)
@@ -4,7 +4,7 @@ error[E0507]: cannot move out of `foo` in pattern guard
 LL |             (|| { let bar = foo; bar.take() })();
    |              ^^             --- move occurs because `foo` has type `&mut Option<&i32>`, which does not implement the `Copy` trait
    |              |
-   |              move out of `foo` occurs here
+   |              `foo` is moved here
    |
    = note: variables bound in patterns cannot be moved from until after the end of the pattern guard
 
@@ -14,7 +14,7 @@ error[E0507]: cannot move out of `foo` in pattern guard
 LL |             (|| { let bar = foo; bar.take() })();
    |              ^^             --- move occurs because `foo` has type `&mut Option<&i32>`, which does not implement the `Copy` trait
    |              |
-   |              move out of `foo` occurs here
+   |              `foo` is moved here
    |
    = note: variables bound in patterns cannot be moved from until after the end of the pattern guard
 
index 60b8dee71a8632e2866abc43561c1b0dd36bd25c..7bdcbcb9c6ef6a43f3876732ac7d7871f778f019 100644 (file)
@@ -74,9 +74,9 @@ error[E0506]: cannot assign to `t` because it is borrowed
   --> $DIR/match-guards-partially-borrow.rs:225:13
    |
 LL |         s if {
-   |         - borrow of `t` occurs here
+   |         - `t` is borrowed here
 LL |             t = !t;
-   |             ^^^^^^ assignment to borrowed `t` occurs here
+   |             ^^^^^^ `t` is assigned to here but it was already borrowed
 LL |             false
 LL |         } => (), // What value should `s` have in the arm?
    |         - borrow later used here
@@ -85,9 +85,9 @@ error[E0506]: cannot assign to `t` because it is borrowed
   --> $DIR/match-guards-partially-borrow.rs:235:13
    |
 LL |         s if let Some(()) = {
-   |         - borrow of `t` occurs here
+   |         - `t` is borrowed here
 LL |             t = !t;
-   |             ^^^^^^ assignment to borrowed `t` occurs here
+   |             ^^^^^^ `t` is assigned to here but it was already borrowed
 LL |             None
 LL |         } => (), // What value should `s` have in the arm?
    |         - borrow later used here
index 32666529f3f957949c5d0e0a427153ee5ac743b9..9273484565a198f72121c73a7022d8dc20781690 100644 (file)
@@ -2,7 +2,7 @@ error[E0503]: cannot use `e` because it was mutably borrowed
   --> $DIR/match-on-borrowed.rs:47:11
    |
 LL |         E::V(ref mut x, _) => x,
-   |              --------- borrow of `e.0` occurs here
+   |              --------- `e.0` is borrowed here
 ...
 LL |     match e { // Don't know that E uses a tag for its discriminant
    |           ^ use of borrowed `e.0`
@@ -14,7 +14,7 @@ error[E0503]: cannot use `*f` because it was mutably borrowed
   --> $DIR/match-on-borrowed.rs:61:11
    |
 LL |         E::V(ref mut x, _) => x,
-   |              --------- borrow of `f.0` occurs here
+   |              --------- `f.0` is borrowed here
 ...
 LL |     match f { // Don't know that E uses a tag for its discriminant
    |           ^ use of borrowed `f.0`
@@ -26,7 +26,7 @@ error[E0503]: cannot use `t` because it was mutably borrowed
   --> $DIR/match-on-borrowed.rs:81:5
    |
 LL |     let x = &mut t;
-   |             ------ borrow of `t` occurs here
+   |             ------ `t` is borrowed here
 LL |     match t {
    |     ^^^^^^^ use of borrowed `t`
 ...
index 80e297807465d6bcde327a5c75f777a1fb56166c..55646b9dca9863a46914eea9483ccdff8735c2d1 100644 (file)
@@ -2,10 +2,10 @@ error[E0506]: cannot assign to `x` because it is borrowed
   --> $DIR/maybe-initialized-drop-implicit-fragment-drop.rs:17:5
    |
 LL |     let wrap = Wrap { p: &mut x };
-   |                          ------ borrow of `x` occurs here
+   |                          ------ `x` is borrowed here
 ...
 LL |     x = 1;
-   |     ^^^^^ assignment to borrowed `x` occurs here
+   |     ^^^^^ `x` is assigned to here but it was already borrowed
 LL |     // FIXME ^ Should not error in the future with implicit dtors, only manually implemented ones
 LL | }
    | - borrow might be used here, when `foo` is dropped and runs the destructor for type `Foo<'_>`
index 14074472eaf88b98d67b3cf01592d6327e12af1f..c89f94a7894f004c46d2d29dacf6778822d6923d 100644 (file)
@@ -2,10 +2,10 @@ error[E0506]: cannot assign to `x` because it is borrowed
   --> $DIR/maybe-initialized-drop-with-fragment.rs:19:5
    |
 LL |     let wrap = Wrap { p: &mut x };
-   |                          ------ borrow of `x` occurs here
+   |                          ------ `x` is borrowed here
 ...
 LL |     x = 1;
-   |     ^^^^^ assignment to borrowed `x` occurs here
+   |     ^^^^^ `x` is assigned to here but it was already borrowed
 LL | }
    | - borrow might be used here, when `foo` is dropped and runs the destructor for type `Foo<'_>`
 
index 91c0afc1dbaa1a22bb2d31ae3938fb0e3291893e..90db13bc5784949f41a745019d94f9e9da4aa155 100644 (file)
@@ -2,10 +2,10 @@ error[E0506]: cannot assign to `x` because it is borrowed
   --> $DIR/maybe-initialized-drop-with-uninitialized-fragments.rs:20:5
    |
 LL |     let wrap = Wrap { p: &mut x };
-   |                          ------ borrow of `x` occurs here
+   |                          ------ `x` is borrowed here
 ...
 LL |     x = 1;
-   |     ^^^^^ assignment to borrowed `x` occurs here
+   |     ^^^^^ `x` is assigned to here but it was already borrowed
 LL |     // FIXME ^ This currently errors and it should not.
 LL | }
    | - borrow might be used here, when `foo` is dropped and runs the destructor for type `Foo<'_>`
index 9825ba4611b7d7b7d26b44ff222bca4827006a4c..15a53a09af8c2ef956babaa9983c9f6d7ffc201c 100644 (file)
@@ -2,9 +2,9 @@ error[E0506]: cannot assign to `x` because it is borrowed
   --> $DIR/maybe-initialized-drop.rs:14:5
    |
 LL |     let wrap = Wrap { p: &mut x };
-   |                          ------ borrow of `x` occurs here
+   |                          ------ `x` is borrowed here
 LL |     x = 1;
-   |     ^^^^^ assignment to borrowed `x` occurs here
+   |     ^^^^^ `x` is assigned to here but it was already borrowed
 LL | }
    | - borrow might be used here, when `wrap` is dropped and runs the `Drop` code for type `Wrap`
 
index fa1a6a9c95786f9457fa8bbfc723d7bc002085b2..534813b2d9f5ae64c8b32f416f6f3a573e57b24e 100644 (file)
@@ -8,7 +8,7 @@ error[E0503]: cannot use `x` because it was mutably borrowed
   --> $DIR/polonius-smoke-test.rs:12:13
    |
 LL |     let y = &mut x;
-   |             ------ borrow of `x` occurs here
+   |             ------ `x` is borrowed here
 LL |     let z = x;
    |             ^ use of borrowed `x`
 LL |     let w = y;
@@ -18,7 +18,9 @@ error[E0505]: cannot move out of `x` because it is borrowed
   --> $DIR/polonius-smoke-test.rs:18:13
    |
 LL | pub fn use_while_mut_fr(x: &mut i32) -> &mut i32 {
-   |                            - let's call the lifetime of this reference `'1`
+   |                         -  - let's call the lifetime of this reference `'1`
+   |                         |
+   |                         binding `x` declared here
 LL |     let y = &mut *x;
    |             ------- borrow of `*x` occurs here
 LL |     let z = x;
@@ -29,6 +31,8 @@ LL |     y
 error[E0505]: cannot move out of `s` because it is borrowed
   --> $DIR/polonius-smoke-test.rs:42:5
    |
+LL |     let s = &mut 1;
+   |         - binding `s` declared here
 LL |     let r = &mut *s;
    |             ------- borrow of `*s` occurs here
 LL |     let tmp = foo(&r);
index df347f4e7f0fec3642272b4b763da71a8da138f2..d111256b8454ff957d1e3aabaa8c798318ef1283 100644 (file)
@@ -4,6 +4,7 @@ error[E0597]: `l` does not live long enough
 LL |     let ptr = {
    |         --- borrow later stored here
 LL |         let l = 3;
+   |             - binding `l` declared here
 LL |         let b = &l;
    |                 ^^ borrowed value does not live long enough
 ...
index 56d878e43033b0f0cfb4f6175848747d457933f5..5672b9cd7e9cc5e96d68e049bafad66c0165953e 100644 (file)
@@ -2,7 +2,7 @@ error[E0503]: cannot use `x` because it was mutably borrowed
   --> $DIR/reference-carried-through-struct-field.rs:6:5
    |
 LL |     let wrapper = Wrap { w: &mut x };
-   |                             ------ borrow of `x` occurs here
+   |                             ------ `x` is borrowed here
 LL |     x += 1;
    |     ^^^^^^ use of borrowed `x`
 LL |     *wrapper.w += 1;
index d032ce6f2132ce21f97cbc1e8bce1a05a4a9a06e..ff6ea598ff46f49f86bdc014b2433ebeb13527ea 100644 (file)
@@ -1,6 +1,9 @@
 error[E0597]: `b` does not live long enough
   --> $DIR/var-appears-twice.rs:20:38
    |
+LL |     let b = 44;
+   |         - binding `b` declared here
+...
 LL |     let x: DoubleCell<_> = make_cell(&b);
    |            -------------             ^^ borrowed value does not live long enough
    |            |
index 253e382511045c4163c152317501755de690b2bd..9e94fd5a7826e3bdc753135a1f2889d056486a9c 100644 (file)
@@ -1,6 +1,8 @@
 error[E0597]: `c` does not live long enough
   --> $DIR/adt-brace-enums.rs:25:48
    |
+LL |     let c = 66;
+   |         - binding `c` declared here
 LL |     SomeEnum::SomeVariant::<&'static u32> { t: &c };
    |                                                ^^
    |                                                |
@@ -15,6 +17,7 @@ error[E0597]: `c` does not live long enough
 LL | fn annot_reference_named_lifetime<'a>(_d: &'a u32) {
    |                                   -- lifetime `'a` defined here
 LL |     let c = 66;
+   |         - binding `c` declared here
 LL |     SomeEnum::SomeVariant::<&'a u32> { t: &c };
    |                                           ^^
    |                                           |
index 8b9d1705df6ad816de949a8b3436d1c93e4bc8a3..cbb7f6a55a989ca60590a6d66fe33783964862d0 100644 (file)
@@ -1,6 +1,8 @@
 error[E0597]: `c` does not live long enough
   --> $DIR/adt-brace-structs.rs:23:37
    |
+LL |     let c = 66;
+   |         - binding `c` declared here
 LL |     SomeStruct::<&'static u32> { t: &c };
    |                                     ^^
    |                                     |
@@ -15,6 +17,7 @@ error[E0597]: `c` does not live long enough
 LL | fn annot_reference_named_lifetime<'a>(_d: &'a u32) {
    |                                   -- lifetime `'a` defined here
 LL |     let c = 66;
+   |         - binding `c` declared here
 LL |     SomeStruct::<&'a u32> { t: &c };
    |                                ^^
    |                                |
index 3326fa521fc9cea4efc8e4d26b039fb90f1c7663..bca85a90d190890db4bd72bb7409a065ed3533f9 100644 (file)
@@ -1,6 +1,8 @@
 error[E0597]: `c` does not live long enough
   --> $DIR/adt-nullary-enums.rs:33:41
    |
+LL |       let c = 66;
+   |           - binding `c` declared here
 LL | /     combine(
 LL | |         SomeEnum::SomeVariant(Cell::new(&c)),
    | |                                         ^^ borrowed value does not live long enough
@@ -15,7 +17,9 @@ error[E0597]: `c` does not live long enough
    |
 LL | fn annot_reference_named_lifetime<'a>(_d: &'a u32) {
    |                                   -- lifetime `'a` defined here
-...
+LL |     let c = 66;
+   |         - binding `c` declared here
+LL |     combine(
 LL |         SomeEnum::SomeVariant(Cell::new(&c)),
    |                               ----------^^-
    |                               |         |
index 2fa7042631d21dd924429e47978eebc11b9c1196..d2d85ec2b9b0f1fc124926f0b2122d2be1ebec3f 100644 (file)
@@ -1,6 +1,8 @@
 error[E0597]: `c` does not live long enough
   --> $DIR/adt-tuple-enums.rs:28:43
    |
+LL |     let c = 66;
+   |         - binding `c` declared here
 LL |     SomeEnum::SomeVariant::<&'static u32>(&c);
    |                                           ^^
    |                                           |
@@ -15,6 +17,7 @@ error[E0597]: `c` does not live long enough
 LL | fn annot_reference_named_lifetime<'a>(_d: &'a u32) {
    |                                   -- lifetime `'a` defined here
 LL |     let c = 66;
+   |         - binding `c` declared here
 LL |     SomeEnum::SomeVariant::<&'a u32>(&c);
    |                                      ^^
    |                                      |
index 9664fb9f548317ea13151a99abb06665b64ab03b..b7bc2a10b7040f434427ca2f6aa2fdffaa9495ee 100644 (file)
@@ -1,6 +1,9 @@
 error[E0597]: `c` does not live long enough
   --> $DIR/adt-tuple-struct-calls.rs:27:7
    |
+LL |     let c = 66;
+   |         - binding `c` declared here
+LL |     let f = SomeStruct::<&'static u32>;
 LL |     f(&c);
    |     --^^-
    |     | |
@@ -14,7 +17,9 @@ error[E0597]: `c` does not live long enough
    |
 LL | fn annot_reference_named_lifetime<'a>(_d: &'a u32) {
    |                                   -- lifetime `'a` defined here
-...
+LL |     let c = 66;
+   |         - binding `c` declared here
+LL |     let f = SomeStruct::<&'a u32>;
 LL |     f(&c);
    |     --^^-
    |     | |
index 76b5252258c7bc3260014944e20b50387cb4291f..97d39da265fe3f810c1812498ebe09ce671c0633 100644 (file)
@@ -1,6 +1,8 @@
 error[E0597]: `c` does not live long enough
   --> $DIR/adt-tuple-struct.rs:23:32
    |
+LL |     let c = 66;
+   |         - binding `c` declared here
 LL |     SomeStruct::<&'static u32>(&c);
    |                                ^^
    |                                |
@@ -15,6 +17,7 @@ error[E0597]: `c` does not live long enough
 LL | fn annot_reference_named_lifetime<'a>(_d: &'a u32) {
    |                                   -- lifetime `'a` defined here
 LL |     let c = 66;
+   |         - binding `c` declared here
 LL |     SomeStruct::<&'a u32>(&c);
    |                           ^^
    |                           |
index 4599d04e7e2300c3eb27ab2121cbc7c17ddf32da..3b9363c41f20fb3741f7b5b12fc913648daacc90 100644 (file)
@@ -1,6 +1,8 @@
 error[E0597]: `x` does not live long enough
   --> $DIR/cast_static_lifetime.rs:5:19
    |
+LL |     let x = 22_u32;
+   |         - binding `x` declared here
 LL |     let y: &u32 = (&x) as &'static u32;
    |                   ^^^^----------------
    |                   |
index 12065a85aa4a0a512872fb8943ecdb3bf92ff4f8..f164255ef305fdb7b1fcc2fadbccdfa7adaa7209 100644 (file)
@@ -1,6 +1,8 @@
 error[E0597]: `x` does not live long enough
   --> $DIR/constant-in-expr-inherent-2.rs:23:9
    |
+LL |     let x = ();
+   |         - binding `x` declared here
 LL |     FUN(&x);
    |     ----^^-
    |     |   |
@@ -13,6 +15,9 @@ LL | }
 error[E0597]: `x` does not live long enough
   --> $DIR/constant-in-expr-inherent-2.rs:24:23
    |
+LL |     let x = ();
+   |         - binding `x` declared here
+LL |     FUN(&x);
 LL |     A::ASSOCIATED_FUN(&x);
    |     ------------------^^-
    |     |                 |
@@ -25,6 +30,9 @@ LL | }
 error[E0597]: `x` does not live long enough
   --> $DIR/constant-in-expr-inherent-2.rs:25:28
    |
+LL |     let x = ();
+   |         - binding `x` declared here
+...
 LL |     B::ALSO_ASSOCIATED_FUN(&x);
    |     -----------------------^^-
    |     |                      |
@@ -37,6 +45,9 @@ LL | }
 error[E0597]: `x` does not live long enough
   --> $DIR/constant-in-expr-inherent-2.rs:26:31
    |
+LL |     let x = ();
+   |         - binding `x` declared here
+...
 LL |     <_>::TRAIT_ASSOCIATED_FUN(&x);
    |     --------------------------^^-
    |     |                         |
index e0640da39e2b62fb3211d3c89e7fdab35b910ab9..8b53e138d9bd0c05e36da6c21e813958641b7f07 100644 (file)
@@ -1,6 +1,8 @@
 error[E0597]: `c` does not live long enough
   --> $DIR/fns.rs:23:29
    |
+LL |     let c = 66;
+   |         - binding `c` declared here
 LL |     some_fn::<&'static u32>(&c);
    |     ------------------------^^-
    |     |                       |
@@ -15,6 +17,7 @@ error[E0597]: `c` does not live long enough
 LL | fn annot_reference_named_lifetime<'a>(_d: &'a u32) {
    |                                   -- lifetime `'a` defined here
 LL |     let c = 66;
+   |         - binding `c` declared here
 LL |     some_fn::<&'a u32>(&c);
    |     -------------------^^-
    |     |                  |
index 10447e45a6d422de9a6ad372f19bf5083a0a1f77..3803cbf776b675e8ef338b8807ee30ce9e6137d3 100644 (file)
@@ -1,6 +1,8 @@
 error[E0597]: `c` does not live long enough
   --> $DIR/method-call.rs:36:34
    |
+LL |     let c = 66;
+   |         - binding `c` declared here
 LL |     a.method::<&'static u32>(b,  &c);
    |     -----------------------------^^-
    |     |                            |
@@ -15,6 +17,8 @@ error[E0597]: `c` does not live long enough
 LL | fn annot_reference_named_lifetime<'a>(_d: &'a u32) {
    |                                   -- lifetime `'a` defined here
 ...
+LL |     let c = 66;
+   |         - binding `c` declared here
 LL |     a.method::<&'a u32>(b,  &c);
    |     ------------------------^^-
    |     |                       |
index 962ddfd2bd151f372c7af5b88dd2dca42808b9cc..c7c08c948abdb20b658857002346ab2a198ca338 100644 (file)
@@ -1,6 +1,9 @@
 error[E0597]: `a` does not live long enough
   --> $DIR/method-ufcs-1.rs:30:7
    |
+LL |     let a = 22;
+   |         - binding `a` declared here
+...
 LL |     x(&a, b, c);
    |     --^^-------
    |     | |
@@ -14,6 +17,8 @@ error[E0597]: `a` does not live long enough
    |
 LL | fn annot_reference_named_lifetime<'a>(_d: &'a u32) {
    |                                   -- lifetime `'a` defined here
+LL |     let a = 22;
+   |         - binding `a` declared here
 ...
 LL |     <&'a u32 as Bazoom<_>>::method(&a, b, c);
    |     -------------------------------^^-------
index 63d59905e1c3892f90fb174794c658e6a6e0ba13..b7861a3bd069ff863cd62293f367aa6b7296042d 100644 (file)
@@ -1,6 +1,9 @@
 error[E0597]: `a` does not live long enough
   --> $DIR/method-ufcs-2.rs:30:7
    |
+LL |     let a = 22;
+   |         - binding `a` declared here
+...
 LL |     x(&a, b, c);
    |     --^^-------
    |     | |
@@ -14,7 +17,10 @@ error[E0597]: `b` does not live long enough
    |
 LL | fn annot_reference_named_lifetime<'a>(_d: &'a u32) {
    |                                   -- lifetime `'a` defined here
-...
+LL |     let a = 22;
+LL |     let b = 44;
+   |         - binding `b` declared here
+LL |     let c = 66;
 LL |     <_ as Bazoom<&'a u32>>::method(a, &b, c);
    |     ----------------------------------^^----
    |     |                                 |
index e7851833e93b23a7f77a130197e6dd19f2dfb33d..8cb995a03ce2ff00054e7c0a369ce4370bf6915e 100644 (file)
@@ -1,6 +1,8 @@
 error[E0597]: `c` does not live long enough
   --> $DIR/method-ufcs-3.rs:36:53
    |
+LL |     let c = 66;
+   |         - binding `c` declared here
 LL |     <_ as Bazoom<_>>::method::<&'static u32>(&a, b, &c);
    |     ------------------------------------------------^^-
    |     |                                               |
@@ -15,6 +17,8 @@ error[E0597]: `c` does not live long enough
 LL | fn annot_reference_named_lifetime<'a>(_d: &'a u32) {
    |                                   -- lifetime `'a` defined here
 ...
+LL |     let c = 66;
+   |         - binding `c` declared here
 LL |     <_ as Bazoom<_>>::method::<&'a u32>(&a, b, &c);
    |     -------------------------------------------^^-
    |     |                                          |
index 94861babd6f320f74b17dee88649a87742560c51..fb26b8d09e179bd8fa732edd24d1fd110627b781 100644 (file)
@@ -4,6 +4,7 @@ error[E0597]: `v` does not live long enough
 LL | fn foo<'a>() {
    |        -- lifetime `'a` defined here
 LL |     let v = 22;
+   |         - binding `v` declared here
 LL |     let x = A::<'a>::new(&v, 22);
    |             -------------^^-----
    |             |            |
index 06f20d9b2355957ec460832005a4aad5947b9770..03b97447e1aa00bcf19da6e2c2c3dd8645607417 100644 (file)
@@ -4,6 +4,7 @@ error[E0597]: `v` does not live long enough
 LL | fn foo<'a>() {
    |        -- lifetime `'a` defined here
 LL |     let v = 22;
+   |         - binding `v` declared here
 LL |     let x = A::<'a>::new::<&'a u32>(&v, &v);
    |             ------------------------^^-----
    |             |                       |
@@ -19,6 +20,7 @@ error[E0597]: `v` does not live long enough
 LL | fn foo<'a>() {
    |        -- lifetime `'a` defined here
 LL |     let v = 22;
+   |         - binding `v` declared here
 LL |     let x = A::<'a>::new::<&'a u32>(&v, &v);
    |             ----------------------------^^-
    |             |                           |
index 4ad61dc81c493911905be8845d6a792e3cec3840..69dd1d1aaae28694f8989172fc7f27766b9528cd 100644 (file)
@@ -4,6 +4,7 @@ error[E0597]: `v` does not live long enough
 LL | fn foo<'a>() {
    |        -- lifetime `'a` defined here
 LL |     let v = 22;
+   |         - binding `v` declared here
 LL |     let x = <A<'a>>::new(&v, 22);
    |             -------------^^-----
    |             |            |
index 0f83e99cdfb92f186eecdecf5c6c085531f0b1ca..66d82bb49dc68cabba031451f44510105eaee1f3 100644 (file)
@@ -4,6 +4,7 @@ error[E0597]: `v` does not live long enough
 LL | fn foo<'a>() {
    |        -- lifetime `'a` defined here
 LL |     let v = 22;
+   |         - binding `v` declared here
 LL |     let x = <A<'a>>::new::<&'a u32>(&v, &v);
    |             ------------------------^^-----
    |             |                       |
@@ -19,6 +20,7 @@ error[E0597]: `v` does not live long enough
 LL | fn foo<'a>() {
    |        -- lifetime `'a` defined here
 LL |     let v = 22;
+   |         - binding `v` declared here
 LL |     let x = <A<'a>>::new::<&'a u32>(&v, &v);
    |             ----------------------------^^-
    |             |                           |
index 975cb4b66d91d0ef91004d6524d5f21786f43878..acc3a1800f4fd8d385faa62b705c6944b8443e2a 100644 (file)
@@ -1,6 +1,8 @@
 error[E0597]: `a` does not live long enough
   --> $DIR/normalization.rs:10:31
    |
+LL |     let a = 22;
+   |         - binding `a` declared here
 LL |     let _: <() as Foo>::Out = &a;
    |            ----------------   ^^ borrowed value does not live long enough
    |            |
@@ -12,6 +14,8 @@ LL | }
 error[E0597]: `a` does not live long enough
   --> $DIR/normalization.rs:13:40
    |
+LL |     let a = 22;
+   |         - binding `a` declared here
 LL |     let _: <&'static () as Foo>::Out = &a;
    |            -------------------------   ^^ borrowed value does not live long enough
    |            |
index a97e7a9fd46fc3a3b1647c5ac17e29f78ba51609..3e7969e117934bad31b598fdf10aba4897e05472 100644 (file)
@@ -1,6 +1,8 @@
 error[E0597]: `y` does not live long enough
   --> $DIR/pattern_substs_on_brace_enum_variant.rs:7:33
    |
+LL |     let y = 22;
+   |         - binding `y` declared here
 LL |     let foo = Foo::Bar { field: &y };
    |                                 ^^ borrowed value does not live long enough
 LL |
@@ -12,6 +14,8 @@ LL | }
 error[E0597]: `y` does not live long enough
   --> $DIR/pattern_substs_on_brace_enum_variant.rs:14:33
    |
+LL |     let y = 22;
+   |         - binding `y` declared here
 LL |     let foo = Foo::Bar { field: &y };
    |                                 ^^ borrowed value does not live long enough
 ...
index 408d7c2a5e2a5c62250df15c5bfb384f48246274..89a1e9545e8af520b3f23213ca3ee88642ba79f6 100644 (file)
@@ -1,6 +1,8 @@
 error[E0597]: `y` does not live long enough
   --> $DIR/pattern_substs_on_brace_struct.rs:5:28
    |
+LL |     let y = 22;
+   |         - binding `y` declared here
 LL |     let foo = Foo { field: &y };
    |                            ^^ borrowed value does not live long enough
 LL |
@@ -12,6 +14,8 @@ LL | }
 error[E0597]: `y` does not live long enough
   --> $DIR/pattern_substs_on_brace_struct.rs:12:28
    |
+LL |     let y = 22;
+   |         - binding `y` declared here
 LL |     let foo = Foo { field: &y };
    |                            ^^ borrowed value does not live long enough
 ...
index 920c906f63a5824a3e08bdf049149f8af153135b..8efeecc77098a93ae9b0d03fd6fd96fa4353a2d1 100644 (file)
@@ -1,6 +1,8 @@
 error[E0597]: `y` does not live long enough
   --> $DIR/pattern_substs_on_tuple_enum_variant.rs:7:24
    |
+LL |     let y = 22;
+   |         - binding `y` declared here
 LL |     let foo = Foo::Bar(&y);
    |                        ^^ borrowed value does not live long enough
 LL |
@@ -12,6 +14,8 @@ LL | }
 error[E0597]: `y` does not live long enough
   --> $DIR/pattern_substs_on_tuple_enum_variant.rs:14:24
    |
+LL |     let y = 22;
+   |         - binding `y` declared here
 LL |     let foo = Foo::Bar(&y);
    |                        ^^ borrowed value does not live long enough
 ...
index 3f01638d84757f6aaee8764ab4c8e56f27d2d7e6..d7f1dac88a618b82b268d97716ceed4101576431 100644 (file)
@@ -1,6 +1,8 @@
 error[E0597]: `y` does not live long enough
   --> $DIR/pattern_substs_on_tuple_struct.rs:5:19
    |
+LL |     let y = 22;
+   |         - binding `y` declared here
 LL |     let foo = Foo(&y);
    |                   ^^ borrowed value does not live long enough
 LL |
@@ -12,6 +14,8 @@ LL | }
 error[E0597]: `y` does not live long enough
   --> $DIR/pattern_substs_on_tuple_struct.rs:12:19
    |
+LL |     let y = 22;
+   |         - binding `y` declared here
 LL |     let foo = Foo(&y);
    |                   ^^ borrowed value does not live long enough
 ...
index de6f8f80fe25248bcac3e425fcd37b9e639fa7fb..8bb714f1d0cdce635e586e53223558eabd522b0b 100644 (file)
@@ -1,6 +1,8 @@
 error[E0597]: `x` does not live long enough
   --> $DIR/patterns.rs:6:9
    |
+LL |     let x = 22;
+   |         - binding `x` declared here
 LL |     let y: &'static u32;
    |            ------------ type annotation requires that `x` is borrowed for `'static`
 LL |     y = &x;
@@ -11,6 +13,8 @@ LL | }
 error[E0597]: `x` does not live long enough
   --> $DIR/patterns.rs:14:9
    |
+LL |     let x = 22;
+   |         - binding `x` declared here
 LL |     let (y, z): (&'static u32, &'static u32);
    |                 ---------------------------- type annotation requires that `x` is borrowed for `'static`
 LL |     y = &x;
@@ -21,6 +25,8 @@ LL | }
 error[E0597]: `x` does not live long enough
   --> $DIR/patterns.rs:20:13
    |
+LL |     let x = 22;
+   |         - binding `x` declared here
 LL |     let y = &x;
    |             ^^ borrowed value does not live long enough
 LL |     let ref z: &'static u32 = y;
@@ -32,6 +38,8 @@ LL | }
 error[E0597]: `x` does not live long enough
   --> $DIR/patterns.rs:39:9
    |
+LL |     let x = 22;
+   |         - binding `x` declared here
 LL |     let Single { value: y }: Single<&'static u32>;
    |                              -------------------- type annotation requires that `x` is borrowed for `'static`
 LL |     y = &x;
@@ -42,6 +50,8 @@ LL | }
 error[E0597]: `x` does not live long enough
   --> $DIR/patterns.rs:51:10
    |
+LL |     let x = 22;
+   |         - binding `x` declared here
 LL |     let Single2 { value: mut _y }: Single2<StaticU32>;
    |                                    ------------------ type annotation requires that `x` is borrowed for `'static`
 LL |     _y = &x;
@@ -52,6 +62,8 @@ LL | }
 error[E0597]: `x` does not live long enough
   --> $DIR/patterns.rs:56:27
    |
+LL |     let x = 22;
+   |         - binding `x` declared here
 LL |     let y: &'static u32 = &x;
    |            ------------   ^^ borrowed value does not live long enough
    |            |
@@ -62,6 +74,8 @@ LL | }
 error[E0597]: `x` does not live long enough
   --> $DIR/patterns.rs:61:27
    |
+LL |     let x = 22;
+   |         - binding `x` declared here
 LL |     let _: &'static u32 = &x;
    |            ------------   ^^ borrowed value does not live long enough
    |            |
@@ -100,6 +114,8 @@ LL |     let (_a, b): (Vec<&'static String>, _) = (vec![&String::new()], 44);
 error[E0597]: `x` does not live long enough
   --> $DIR/patterns.rs:75:40
    |
+LL |     let x = 22;
+   |         - binding `x` declared here
 LL |     let (_, _): (&'static u32, u32) = (&x, 44);
    |                 -------------------    ^^ borrowed value does not live long enough
    |                 |
@@ -110,6 +126,8 @@ LL | }
 error[E0597]: `x` does not live long enough
   --> $DIR/patterns.rs:80:40
    |
+LL |     let x = 22;
+   |         - binding `x` declared here
 LL |     let (y, _): (&'static u32, u32) = (&x, 44);
    |                 -------------------    ^^ borrowed value does not live long enough
    |                 |
@@ -120,6 +138,8 @@ LL | }
 error[E0597]: `x` does not live long enough
   --> $DIR/patterns.rs:85:69
    |
+LL |     let x = 22;
+   |         - binding `x` declared here
 LL |     let Single { value: y }: Single<&'static u32> = Single { value: &x };
    |                              --------------------                   ^^ borrowed value does not live long enough
    |                              |
@@ -130,6 +150,8 @@ LL | }
 error[E0597]: `x` does not live long enough
   --> $DIR/patterns.rs:90:69
    |
+LL |     let x = 22;
+   |         - binding `x` declared here
 LL |     let Single { value: _ }: Single<&'static u32> = Single { value: &x };
    |                              --------------------                   ^^ borrowed value does not live long enough
    |                              |
@@ -140,6 +162,8 @@ LL | }
 error[E0597]: `x` does not live long enough
   --> $DIR/patterns.rs:98:17
    |
+LL |     let x = 22;
+   |         - binding `x` declared here
 LL |     let Double { value1: _, value2: _ }: Double<&'static u32> = Double {
    |                                          -------------------- type annotation requires that `x` is borrowed for `'static`
 LL |         value1: &x,
index cb99a6a369d0b25a12b4a4656b128c832335ea36..132a00ba41581da4175c9f0c5565bd690ba7a3c0 100644 (file)
@@ -4,6 +4,7 @@ error[E0597]: `x` does not live long enough
 LL | fn foo<'a>() {
    |        -- lifetime `'a` defined here
 LL |     let x = 0;
+   |         - binding `x` declared here
 LL |     let f = &drop::<&'a i32>;
    |             ---------------- assignment requires that `x` is borrowed for `'a`
 LL |     f(&x);
index ccbf3c1d927c6b02e29571a8645a45b8458df656..766877f8835c414bb59c60c9cee536b8b285b12a 100644 (file)
@@ -1,6 +1,8 @@
 error[E0597]: `x` does not live long enough
   --> $DIR/type_ascription_static_lifetime.rs:6:33
    |
+LL |     let x = 22_u32;
+   |         - binding `x` declared here
 LL |     let y: &u32 = type_ascribe!(&x, &'static u32);
    |                   --------------^^---------------
    |                   |             |
diff --git a/tests/ui/non-ice-error-on-worker-io-fail.rs b/tests/ui/non-ice-error-on-worker-io-fail.rs
deleted file mode 100644 (file)
index 134e7d4..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-// Issue #66530: We would ICE if someone compiled with `-o /dev/null`,
-// because we would try to generate auxiliary files in `/dev/` (which
-// at least the OS X file system rejects).
-//
-// An attempt to `-o` into a directory we cannot write into should indeed
-// be an error; but not an ICE.
-//
-// However, some folks run tests as root, which can write `/dev/` and end
-// up clobbering `/dev/null`. Instead we'll use a non-existent path, which
-// also used to ICE, but even root can't magically write there.
-
-// compile-flags: -o /does-not-exist/output
-
-// The error-pattern check occurs *before* normalization, and the error patterns
-// are wildly different between build environments. So this is a cop-out (and we
-// rely on the checking of the normalized stderr output as our actual
-// "verification" of the diagnostic).
-
-// error-pattern: error
-
-// On Mac OS X, we get an error like the below
-// normalize-stderr-test "failed to write bytecode to /does-not-exist/output.non_ice_error_on_worker_io_fail.*" -> "io error modifying /does-not-exist/"
-
-// On Linux, we get an error like the below
-// normalize-stderr-test "couldn't create a temp dir.*" -> "io error modifying /does-not-exist/"
-
-// ignore-windows - this is a unix-specific test
-// ignore-emscripten - the file-system issues do not replicate here
-// ignore-wasm - the file-system issues do not replicate here
-// ignore-arm - the file-system issues do not replicate here, at least on armhf-gnu
-
-#![crate_type="lib"]
-
-#![cfg_attr(not(feature = "std"), no_std)]
-pub mod task {
-    pub mod __internal {
-        use crate::task::Waker;
-    }
-    pub use core::task::Waker;
-}
diff --git a/tests/ui/non-ice-error-on-worker-io-fail.stderr b/tests/ui/non-ice-error-on-worker-io-fail.stderr
deleted file mode 100644 (file)
index edadecf..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-warning: ignoring --out-dir flag due to -o flag
-
-error: io error modifying /does-not-exist/
-
-error: aborting due to previous error; 1 warning emitted
-
diff --git a/tests/ui/parser/anon-enums.rs b/tests/ui/parser/anon-enums.rs
new file mode 100644 (file)
index 0000000..56b8a3d
--- /dev/null
@@ -0,0 +1,17 @@
+fn foo(x: bool | i32) -> i32 | f64 {
+//~^ ERROR anonymous enums are not supported
+//~| ERROR anonymous enums are not supported
+    match x {
+        x: i32 => x, //~ ERROR expected
+        true => 42.,
+        false => 0.333,
+    }
+}
+
+fn main() {
+    match foo(true) {
+        42: i32 => (), //~ ERROR expected
+        _: f64 => (), //~ ERROR expected
+        x: i32 => (), //~ ERROR expected
+    }
+}
diff --git a/tests/ui/parser/anon-enums.stderr b/tests/ui/parser/anon-enums.stderr
new file mode 100644 (file)
index 0000000..8415822
--- /dev/null
@@ -0,0 +1,68 @@
+error: anonymous enums are not supported
+  --> $DIR/anon-enums.rs:1:16
+   |
+LL | fn foo(x: bool | i32) -> i32 | f64 {
+   |           ---- ^ ---
+   |
+   = help: create a named `enum` and use it here instead:
+           enum Name {
+               Variant1(bool),
+               Variant2(i32),
+           }
+
+error: anonymous enums are not supported
+  --> $DIR/anon-enums.rs:1:30
+   |
+LL | fn foo(x: bool | i32) -> i32 | f64 {
+   |                          --- ^ ---
+   |
+   = help: create a named `enum` and use it here instead:
+           enum Name {
+               Variant1(i32),
+               Variant2(f64),
+           }
+
+error: expected one of `@` or `|`, found `:`
+  --> $DIR/anon-enums.rs:5:10
+   |
+LL |         x: i32 => x,
+   |          ^ --- specifying the type of a pattern isn't supported
+   |          |
+   |          expected one of `@` or `|`
+   |
+help: maybe write a path separator here
+   |
+LL |         x::i32 => x,
+   |          ~~
+
+error: expected one of `...`, `..=`, `..`, or `|`, found `:`
+  --> $DIR/anon-enums.rs:13:11
+   |
+LL |         42: i32 => (),
+   |           ^ --- specifying the type of a pattern isn't supported
+   |           |
+   |           expected one of `...`, `..=`, `..`, or `|`
+
+error: expected `|`, found `:`
+  --> $DIR/anon-enums.rs:14:10
+   |
+LL |         _: f64 => (),
+   |          ^ --- specifying the type of a pattern isn't supported
+   |          |
+   |          expected `|`
+
+error: expected one of `@` or `|`, found `:`
+  --> $DIR/anon-enums.rs:15:10
+   |
+LL |         x: i32 => (),
+   |          ^ --- specifying the type of a pattern isn't supported
+   |          |
+   |          expected one of `@` or `|`
+   |
+help: maybe write a path separator here
+   |
+LL |         x::i32 => (),
+   |          ~~
+
+error: aborting due to 6 previous errors
+
diff --git a/tests/ui/parser/fake-anon-enums-in-macros.rs b/tests/ui/parser/fake-anon-enums-in-macros.rs
new file mode 100644 (file)
index 0000000..38fe8de
--- /dev/null
@@ -0,0 +1,20 @@
+// build-pass
+macro_rules! check_ty {
+    ($Z:ty) => { compile_error!("triggered"); };
+    ($X:ty | $Y:ty) => { $X };
+}
+
+macro_rules! check {
+    ($Z:ty) => { compile_error!("triggered"); };
+    ($X:ty | $Y:ty) => { };
+}
+
+check! { i32 | u8 }
+
+fn foo(x: check_ty! { i32 | u8 }) -> check_ty! { i32 | u8 } {
+    x
+}
+fn main() {
+    let x: check_ty! { i32 | u8 } = 42;
+    let _: check_ty! { i32 | u8 } = foo(x);
+}
index 0b7b67496d6f32df39107feb43e1c957a029ae21..e1ea38f2795df698983f335bbf6b77f13d29dad1 100644 (file)
@@ -68,7 +68,6 @@ fn main() {
         Foo:Bar::Baz => {}
         //~^ ERROR: expected one of
         //~| HELP: maybe write a path separator here
-        //~| ERROR: failed to resolve: `Bar` is a variant, not a module
     }
     match myfoo {
         Foo::Bar => {}
index 2050a16beb34983c63e96f847a82c1d23f3f16d5..63b072ac4cdc68c6c4f9ec8734f49945c45de38e 100644 (file)
@@ -2,89 +2,118 @@ error: expected one of `@` or `|`, found `:`
   --> $DIR/issue-87086-colon-path-sep.rs:17:12
    |
 LL |         Foo:Bar => {}
-   |            ^
+   |            ^--- specifying the type of a pattern isn't supported
    |            |
    |            expected one of `@` or `|`
-   |            help: maybe write a path separator here: `::`
+   |
+help: maybe write a path separator here
+   |
+LL |         Foo::Bar => {}
+   |            ~~
 
 error: expected one of `!`, `(`, `...`, `..=`, `..`, `::`, `{`, or `|`, found `:`
   --> $DIR/issue-87086-colon-path-sep.rs:23:17
    |
 LL |         qux::Foo:Bar => {}
-   |                 ^
+   |                 ^--- specifying the type of a pattern isn't supported
    |                 |
    |                 expected one of 8 possible tokens
-   |                 help: maybe write a path separator here: `::`
+   |
+help: maybe write a path separator here
+   |
+LL |         qux::Foo::Bar => {}
+   |                 ~~
 
 error: expected one of `@` or `|`, found `:`
   --> $DIR/issue-87086-colon-path-sep.rs:29:12
    |
 LL |         qux:Foo::Baz => {}
-   |            ^
+   |            ^-------- specifying the type of a pattern isn't supported
    |            |
    |            expected one of `@` or `|`
-   |            help: maybe write a path separator here: `::`
+   |
+help: maybe write a path separator here
+   |
+LL |         qux::Foo::Baz => {}
+   |            ~~
 
 error: expected one of `@` or `|`, found `:`
   --> $DIR/issue-87086-colon-path-sep.rs:35:12
    |
 LL |         qux: Foo::Baz if true => {}
-   |            ^
+   |            ^ -------- specifying the type of a pattern isn't supported
    |            |
    |            expected one of `@` or `|`
-   |            help: maybe write a path separator here: `::`
+   |
+help: maybe write a path separator here
+   |
+LL |         qux::Foo::Baz if true => {}
+   |            ~~
 
 error: expected one of `@` or `|`, found `:`
   --> $DIR/issue-87086-colon-path-sep.rs:40:15
    |
 LL |     if let Foo:Bar = f() {
-   |               ^
+   |               ^--- specifying the type of a pattern isn't supported
    |               |
    |               expected one of `@` or `|`
-   |               help: maybe write a path separator here: `::`
+   |
+help: maybe write a path separator here
+   |
+LL |     if let Foo::Bar = f() {
+   |               ~~
 
 error: expected one of `@` or `|`, found `:`
   --> $DIR/issue-87086-colon-path-sep.rs:48:16
    |
 LL |         ref qux: Foo::Baz => {}
-   |                ^
+   |                ^ -------- specifying the type of a pattern isn't supported
    |                |
    |                expected one of `@` or `|`
-   |                help: maybe write a path separator here: `::`
+   |
+help: maybe write a path separator here
+   |
+LL |         ref qux::Foo::Baz => {}
+   |                ~~
 
 error: expected one of `@` or `|`, found `:`
   --> $DIR/issue-87086-colon-path-sep.rs:57:16
    |
 LL |         mut qux: Foo::Baz => {}
-   |                ^
+   |                ^ -------- specifying the type of a pattern isn't supported
    |                |
    |                expected one of `@` or `|`
-   |                help: maybe write a path separator here: `::`
+   |
+help: maybe write a path separator here
+   |
+LL |         mut qux::Foo::Baz => {}
+   |                ~~
 
 error: expected one of `@` or `|`, found `:`
   --> $DIR/issue-87086-colon-path-sep.rs:68:12
    |
 LL |         Foo:Bar::Baz => {}
-   |            ^
+   |            ^-------- specifying the type of a pattern isn't supported
    |            |
    |            expected one of `@` or `|`
-   |            help: maybe write a path separator here: `::`
+   |
+help: maybe write a path separator here
+   |
+LL |         Foo::Bar::Baz => {}
+   |            ~~
 
 error: expected one of `@` or `|`, found `:`
-  --> $DIR/issue-87086-colon-path-sep.rs:75:12
+  --> $DIR/issue-87086-colon-path-sep.rs:74:12
    |
 LL |         Foo:Bar => {}
-   |            ^
+   |            ^--- specifying the type of a pattern isn't supported
    |            |
    |            expected one of `@` or `|`
-   |            help: maybe write a path separator here: `::`
-
-error[E0433]: failed to resolve: `Bar` is a variant, not a module
-  --> $DIR/issue-87086-colon-path-sep.rs:68:13
    |
-LL |         Foo:Bar::Baz => {}
-   |             ^^^ `Bar` is a variant, not a module
+help: maybe write a path separator here
+   |
+LL |         Foo::Bar => {}
+   |            ~~
 
-error: aborting due to 10 previous errors
+error: aborting due to 9 previous errors
 
-For more information about this error, try `rustc --explain E0433`.
index c8b45fd24d98c00c916c3b7b292ecf6be0d7c480..29cd6c45c34b58410d02148ea7ca9b83754a7ae4 100644 (file)
@@ -4,8 +4,8 @@ error: cannot move out of value because it is borrowed
 LL |         Some(ref _y @ _z) => {}
    |              ------^^^--
    |              |        |
-   |              |        value moved into `_z` here
-   |              value borrowed, by `_y`, here
+   |              |        value is moved into `_z` here
+   |              value is borrowed by `_y` here
 
 error: borrow of moved value
   --> $DIR/bind-by-move-neither-can-live-while-the-other-survives-1.rs:19:14
@@ -28,8 +28,8 @@ error: cannot move out of value because it is borrowed
 LL |         Some(ref mut _y @ _z) => {}
    |              ----------^^^--
    |              |            |
-   |              |            value moved into `_z` here
-   |              value borrowed, by `_y`, here
+   |              |            value is moved into `_z` here
+   |              value is mutably borrowed by `_y` here
 
 error: borrow of moved value
   --> $DIR/bind-by-move-neither-can-live-while-the-other-survives-1.rs:33:14
index f27df32ccfa5ce2afbe63b73b2f62255371b7228..2c123b01e173e7c12f5217aebd80ef72001692f2 100644 (file)
@@ -4,8 +4,8 @@ error: cannot move out of value because it is borrowed
 LL |     let ref a @ box b = Box::new(NC);
    |         -----^^^^^^^-
    |         |           |
-   |         |           value moved into `b` here
-   |         value borrowed, by `a`, here
+   |         |           value is moved into `b` here
+   |         value is borrowed by `a` here
 
 error: cannot borrow value as mutable because it is also borrowed as immutable
   --> $DIR/borrowck-pat-at-and-box.rs:34:9
@@ -13,8 +13,8 @@ error: cannot borrow value as mutable because it is also borrowed as immutable
 LL |     let ref a @ box ref mut b = Box::new(nc());
    |         -----^^^^^^^---------
    |         |           |
-   |         |           mutable borrow, by `b`, occurs here
-   |         immutable borrow, by `a`, occurs here
+   |         |           value is mutably borrowed by `b` here
+   |         value is borrowed by `a` here
 
 error: cannot borrow value as mutable because it is also borrowed as immutable
   --> $DIR/borrowck-pat-at-and-box.rs:36:9
@@ -22,8 +22,8 @@ error: cannot borrow value as mutable because it is also borrowed as immutable
 LL |     let ref a @ box ref mut b = Box::new(NC);
    |         -----^^^^^^^---------
    |         |           |
-   |         |           mutable borrow, by `b`, occurs here
-   |         immutable borrow, by `a`, occurs here
+   |         |           value is mutably borrowed by `b` here
+   |         value is borrowed by `a` here
 
 error: cannot borrow value as mutable because it is also borrowed as immutable
   --> $DIR/borrowck-pat-at-and-box.rs:38:9
@@ -31,8 +31,8 @@ error: cannot borrow value as mutable because it is also borrowed as immutable
 LL |     let ref a @ box ref mut b = Box::new(NC);
    |         -----^^^^^^^---------
    |         |           |
-   |         |           mutable borrow, by `b`, occurs here
-   |         immutable borrow, by `a`, occurs here
+   |         |           value is mutably borrowed by `b` here
+   |         value is borrowed by `a` here
 
 error: cannot borrow value as mutable because it is also borrowed as immutable
   --> $DIR/borrowck-pat-at-and-box.rs:42:9
@@ -40,8 +40,8 @@ error: cannot borrow value as mutable because it is also borrowed as immutable
 LL |     let ref a @ box ref mut b = Box::new(NC);
    |         -----^^^^^^^---------
    |         |           |
-   |         |           mutable borrow, by `b`, occurs here
-   |         immutable borrow, by `a`, occurs here
+   |         |           value is mutably borrowed by `b` here
+   |         value is borrowed by `a` here
 
 error: cannot borrow value as immutable because it is also borrowed as mutable
   --> $DIR/borrowck-pat-at-and-box.rs:48:9
@@ -49,8 +49,8 @@ error: cannot borrow value as immutable because it is also borrowed as mutable
 LL |     let ref mut a @ box ref b = Box::new(NC);
    |         ---------^^^^^^^-----
    |         |               |
-   |         |               immutable borrow, by `b`, occurs here
-   |         mutable borrow, by `a`, occurs here
+   |         |               value is borrowed by `b` here
+   |         value is mutably borrowed by `a` here
 
 error: cannot borrow value as immutable because it is also borrowed as mutable
   --> $DIR/borrowck-pat-at-and-box.rs:62:9
@@ -58,8 +58,8 @@ error: cannot borrow value as immutable because it is also borrowed as mutable
 LL |         ref mut a @ box ref b => {
    |         ---------^^^^^^^-----
    |         |               |
-   |         |               immutable borrow, by `b`, occurs here
-   |         mutable borrow, by `a`, occurs here
+   |         |               value is borrowed by `b` here
+   |         value is mutably borrowed by `a` here
 
 error: cannot borrow value as immutable because it is also borrowed as mutable
   --> $DIR/borrowck-pat-at-and-box.rs:54:11
@@ -67,8 +67,8 @@ error: cannot borrow value as immutable because it is also borrowed as mutable
 LL |     fn f5(ref mut a @ box ref b: Box<NC>) {
    |           ---------^^^^^^^-----
    |           |               |
-   |           |               immutable borrow, by `b`, occurs here
-   |           mutable borrow, by `a`, occurs here
+   |           |               value is borrowed by `b` here
+   |           value is mutably borrowed by `a` here
 
 error[E0382]: borrow of moved value
   --> $DIR/borrowck-pat-at-and-box.rs:31:9
index 770bb89530ccaa60c2a1b63605854ca5f76e29f9..4f7fbc9e04b04591f7f3bf967ef57fbd64ffa8ec 100644 (file)
@@ -4,8 +4,8 @@ error: cannot move out of value because it is borrowed
 LL |     let ref a @ b = U;
    |         -----^^^-
    |         |       |
-   |         |       value moved into `b` here
-   |         value borrowed, by `a`, here
+   |         |       value is moved into `b` here
+   |         value is borrowed by `a` here
 
 error: cannot move out of value because it is borrowed
   --> $DIR/borrowck-pat-by-move-and-ref.rs:26:9
@@ -13,9 +13,9 @@ error: cannot move out of value because it is borrowed
 LL |     let ref a @ (ref b @ mut c, ref d @ e) = (U, U);
    |         -----^^^^^^^^^^^^-----^^^^^^^^^^-^
    |         |                |              |
-   |         |                |              value moved into `e` here
-   |         |                value moved into `c` here
-   |         value borrowed, by `a`, here
+   |         |                |              value is moved into `e` here
+   |         |                value is moved into `c` here
+   |         value is borrowed by `a` here
 
 error: cannot move out of value because it is borrowed
   --> $DIR/borrowck-pat-by-move-and-ref.rs:26:18
@@ -23,8 +23,8 @@ error: cannot move out of value because it is borrowed
 LL |     let ref a @ (ref b @ mut c, ref d @ e) = (U, U);
    |                  -----^^^-----
    |                  |       |
-   |                  |       value moved into `c` here
-   |                  value borrowed, by `b`, here
+   |                  |       value is moved into `c` here
+   |                  value is borrowed by `b` here
 
 error: cannot move out of value because it is borrowed
   --> $DIR/borrowck-pat-by-move-and-ref.rs:26:33
@@ -32,8 +32,8 @@ error: cannot move out of value because it is borrowed
 LL |     let ref a @ (ref b @ mut c, ref d @ e) = (U, U);
    |                                 -----^^^-
    |                                 |       |
-   |                                 |       value moved into `e` here
-   |                                 value borrowed, by `d`, here
+   |                                 |       value is moved into `e` here
+   |                                 value is borrowed by `d` here
 
 error: cannot move out of value because it is borrowed
   --> $DIR/borrowck-pat-by-move-and-ref.rs:30:9
@@ -41,9 +41,9 @@ error: cannot move out of value because it is borrowed
 LL |     let ref mut a @ [b, mut c] = [U, U];
    |         ---------^^^^-^^-----^
    |         |            |  |
-   |         |            |  value moved into `c` here
-   |         |            value moved into `b` here
-   |         value borrowed, by `a`, here
+   |         |            |  value is moved into `c` here
+   |         |            value is moved into `b` here
+   |         value is mutably borrowed by `a` here
 
 error: cannot move out of value because it is borrowed
   --> $DIR/borrowck-pat-by-move-and-ref.rs:33:9
@@ -51,8 +51,8 @@ error: cannot move out of value because it is borrowed
 LL |     let ref a @ b = u();
    |         -----^^^-
    |         |       |
-   |         |       value moved into `b` here
-   |         value borrowed, by `a`, here
+   |         |       value is moved into `b` here
+   |         value is borrowed by `a` here
 
 error: cannot move out of value because it is borrowed
   --> $DIR/borrowck-pat-by-move-and-ref.rs:36:9
@@ -60,9 +60,9 @@ error: cannot move out of value because it is borrowed
 LL |     let ref a @ (ref b @ mut c, ref d @ e) = (u(), u());
    |         -----^^^^^^^^^^^^-----^^^^^^^^^^-^
    |         |                |              |
-   |         |                |              value moved into `e` here
-   |         |                value moved into `c` here
-   |         value borrowed, by `a`, here
+   |         |                |              value is moved into `e` here
+   |         |                value is moved into `c` here
+   |         value is borrowed by `a` here
 
 error: cannot move out of value because it is borrowed
   --> $DIR/borrowck-pat-by-move-and-ref.rs:36:18
@@ -70,8 +70,8 @@ error: cannot move out of value because it is borrowed
 LL |     let ref a @ (ref b @ mut c, ref d @ e) = (u(), u());
    |                  -----^^^-----
    |                  |       |
-   |                  |       value moved into `c` here
-   |                  value borrowed, by `b`, here
+   |                  |       value is moved into `c` here
+   |                  value is borrowed by `b` here
 
 error: cannot move out of value because it is borrowed
   --> $DIR/borrowck-pat-by-move-and-ref.rs:36:33
@@ -79,8 +79,8 @@ error: cannot move out of value because it is borrowed
 LL |     let ref a @ (ref b @ mut c, ref d @ e) = (u(), u());
    |                                 -----^^^-
    |                                 |       |
-   |                                 |       value moved into `e` here
-   |                                 value borrowed, by `d`, here
+   |                                 |       value is moved into `e` here
+   |                                 value is borrowed by `d` here
 
 error: cannot move out of value because it is borrowed
   --> $DIR/borrowck-pat-by-move-and-ref.rs:42:9
@@ -88,9 +88,9 @@ error: cannot move out of value because it is borrowed
 LL |     let ref mut a @ [b, mut c] = [u(), u()];
    |         ---------^^^^-^^-----^
    |         |            |  |
-   |         |            |  value moved into `c` here
-   |         |            value moved into `b` here
-   |         value borrowed, by `a`, here
+   |         |            |  value is moved into `c` here
+   |         |            value is moved into `b` here
+   |         value is mutably borrowed by `a` here
 
 error: cannot move out of value because it is borrowed
   --> $DIR/borrowck-pat-by-move-and-ref.rs:47:9
@@ -98,8 +98,8 @@ error: cannot move out of value because it is borrowed
 LL |         ref a @ Some(b) => {}
    |         -----^^^^^^^^-^
    |         |            |
-   |         |            value moved into `b` here
-   |         value borrowed, by `a`, here
+   |         |            value is moved into `b` here
+   |         value is borrowed by `a` here
 
 error: cannot move out of value because it is borrowed
   --> $DIR/borrowck-pat-by-move-and-ref.rs:52:9
@@ -107,9 +107,9 @@ error: cannot move out of value because it is borrowed
 LL |         ref a @ Some((ref b @ mut c, ref d @ e)) => {}
    |         -----^^^^^^^^^^^^^^^^^-----^^^^^^^^^^-^^
    |         |                     |              |
-   |         |                     |              value moved into `e` here
-   |         |                     value moved into `c` here
-   |         value borrowed, by `a`, here
+   |         |                     |              value is moved into `e` here
+   |         |                     value is moved into `c` here
+   |         value is borrowed by `a` here
 
 error: cannot move out of value because it is borrowed
   --> $DIR/borrowck-pat-by-move-and-ref.rs:52:23
@@ -117,8 +117,8 @@ error: cannot move out of value because it is borrowed
 LL |         ref a @ Some((ref b @ mut c, ref d @ e)) => {}
    |                       -----^^^-----
    |                       |       |
-   |                       |       value moved into `c` here
-   |                       value borrowed, by `b`, here
+   |                       |       value is moved into `c` here
+   |                       value is borrowed by `b` here
 
 error: cannot move out of value because it is borrowed
   --> $DIR/borrowck-pat-by-move-and-ref.rs:52:38
@@ -126,8 +126,8 @@ error: cannot move out of value because it is borrowed
 LL |         ref a @ Some((ref b @ mut c, ref d @ e)) => {}
    |                                      -----^^^-
    |                                      |       |
-   |                                      |       value moved into `e` here
-   |                                      value borrowed, by `d`, here
+   |                                      |       value is moved into `e` here
+   |                                      value is borrowed by `d` here
 
 error: cannot move out of value because it is borrowed
   --> $DIR/borrowck-pat-by-move-and-ref.rs:59:9
@@ -135,9 +135,9 @@ error: cannot move out of value because it is borrowed
 LL |         ref mut a @ Some([b, mut c]) => {}
    |         ---------^^^^^^^^^-^^-----^^
    |         |                 |  |
-   |         |                 |  value moved into `c` here
-   |         |                 value moved into `b` here
-   |         value borrowed, by `a`, here
+   |         |                 |  value is moved into `c` here
+   |         |                 value is moved into `b` here
+   |         value is mutably borrowed by `a` here
 
 error: cannot move out of value because it is borrowed
   --> $DIR/borrowck-pat-by-move-and-ref.rs:64:9
@@ -145,8 +145,8 @@ error: cannot move out of value because it is borrowed
 LL |         ref a @ Some(b) => {}
    |         -----^^^^^^^^-^
    |         |            |
-   |         |            value moved into `b` here
-   |         value borrowed, by `a`, here
+   |         |            value is moved into `b` here
+   |         value is borrowed by `a` here
 
 error: cannot move out of value because it is borrowed
   --> $DIR/borrowck-pat-by-move-and-ref.rs:69:9
@@ -154,9 +154,9 @@ error: cannot move out of value because it is borrowed
 LL |         ref a @ Some((ref b @ mut c, ref d @ e)) => {}
    |         -----^^^^^^^^^^^^^^^^^-----^^^^^^^^^^-^^
    |         |                     |              |
-   |         |                     |              value moved into `e` here
-   |         |                     value moved into `c` here
-   |         value borrowed, by `a`, here
+   |         |                     |              value is moved into `e` here
+   |         |                     value is moved into `c` here
+   |         value is borrowed by `a` here
 
 error: cannot move out of value because it is borrowed
   --> $DIR/borrowck-pat-by-move-and-ref.rs:69:23
@@ -164,8 +164,8 @@ error: cannot move out of value because it is borrowed
 LL |         ref a @ Some((ref b @ mut c, ref d @ e)) => {}
    |                       -----^^^-----
    |                       |       |
-   |                       |       value moved into `c` here
-   |                       value borrowed, by `b`, here
+   |                       |       value is moved into `c` here
+   |                       value is borrowed by `b` here
 
 error: cannot move out of value because it is borrowed
   --> $DIR/borrowck-pat-by-move-and-ref.rs:69:38
@@ -173,8 +173,8 @@ error: cannot move out of value because it is borrowed
 LL |         ref a @ Some((ref b @ mut c, ref d @ e)) => {}
    |                                      -----^^^-
    |                                      |       |
-   |                                      |       value moved into `e` here
-   |                                      value borrowed, by `d`, here
+   |                                      |       value is moved into `e` here
+   |                                      value is borrowed by `d` here
 
 error: cannot move out of value because it is borrowed
   --> $DIR/borrowck-pat-by-move-and-ref.rs:78:9
@@ -182,9 +182,9 @@ error: cannot move out of value because it is borrowed
 LL |         ref mut a @ Some([b, mut c]) => {}
    |         ---------^^^^^^^^^-^^-----^^
    |         |                 |  |
-   |         |                 |  value moved into `c` here
-   |         |                 value moved into `b` here
-   |         value borrowed, by `a`, here
+   |         |                 |  value is moved into `c` here
+   |         |                 value is moved into `b` here
+   |         value is mutably borrowed by `a` here
 
 error: cannot move out of value because it is borrowed
   --> $DIR/borrowck-pat-by-move-and-ref.rs:11:11
@@ -192,8 +192,8 @@ error: cannot move out of value because it is borrowed
 LL |     fn f1(ref a @ b: U) {}
    |           -----^^^-
    |           |       |
-   |           |       value moved into `b` here
-   |           value borrowed, by `a`, here
+   |           |       value is moved into `b` here
+   |           value is borrowed by `a` here
 
 error: cannot move out of value because it is borrowed
   --> $DIR/borrowck-pat-by-move-and-ref.rs:14:11
@@ -201,9 +201,9 @@ error: cannot move out of value because it is borrowed
 LL |     fn f2(ref a @ (ref b @ mut c, ref d @ e): (U, U)) {}
    |           -----^^^^^^^^^^^^-----^^^^^^^^^^-^
    |           |                |              |
-   |           |                |              value moved into `e` here
-   |           |                value moved into `c` here
-   |           value borrowed, by `a`, here
+   |           |                |              value is moved into `e` here
+   |           |                value is moved into `c` here
+   |           value is borrowed by `a` here
 
 error: cannot move out of value because it is borrowed
   --> $DIR/borrowck-pat-by-move-and-ref.rs:14:20
@@ -211,8 +211,8 @@ error: cannot move out of value because it is borrowed
 LL |     fn f2(ref a @ (ref b @ mut c, ref d @ e): (U, U)) {}
    |                    -----^^^-----
    |                    |       |
-   |                    |       value moved into `c` here
-   |                    value borrowed, by `b`, here
+   |                    |       value is moved into `c` here
+   |                    value is borrowed by `b` here
 
 error: cannot move out of value because it is borrowed
   --> $DIR/borrowck-pat-by-move-and-ref.rs:14:35
@@ -220,8 +220,8 @@ error: cannot move out of value because it is borrowed
 LL |     fn f2(ref a @ (ref b @ mut c, ref d @ e): (U, U)) {}
    |                                   -----^^^-
    |                                   |       |
-   |                                   |       value moved into `e` here
-   |                                   value borrowed, by `d`, here
+   |                                   |       value is moved into `e` here
+   |                                   value is borrowed by `d` here
 
 error: cannot move out of value because it is borrowed
   --> $DIR/borrowck-pat-by-move-and-ref.rs:20:11
@@ -229,9 +229,9 @@ error: cannot move out of value because it is borrowed
 LL |     fn f3(ref mut a @ [b, mut c]: [U; 2]) {}
    |           ---------^^^^-^^-----^
    |           |            |  |
-   |           |            |  value moved into `c` here
-   |           |            value moved into `b` here
-   |           value borrowed, by `a`, here
+   |           |            |  value is moved into `c` here
+   |           |            value is moved into `b` here
+   |           value is mutably borrowed by `a` here
 
 error[E0382]: borrow of partially moved value
   --> $DIR/borrowck-pat-by-move-and-ref.rs:30:9
index 8546b4bb477349d7b29391a5e64824efc6e20e07..f51b5041858c6ac43f01a7811839e925e8119791 100644 (file)
@@ -4,8 +4,8 @@ error: cannot borrow value as immutable because it is also borrowed as mutable
 LL |         ref mut z @ &mut Some(ref a) => {
    |         ---------^^^^^^^^^^^^^-----^
    |         |                     |
-   |         |                     immutable borrow, by `a`, occurs here
-   |         mutable borrow, by `z`, occurs here
+   |         |                     value is borrowed by `a` here
+   |         value is mutably borrowed by `z` here
 
 error: cannot borrow value as mutable more than once at a time
   --> $DIR/borrowck-pat-ref-mut-and-ref.rs:33:9
@@ -13,9 +13,9 @@ error: cannot borrow value as mutable more than once at a time
 LL |     let ref mut a @ (ref b @ ref mut c) = u(); // sub-in-sub
    |         ---------^^^^-----------------^
    |         |            |       |
-   |         |            |       another mutable borrow, by `c`, occurs here
-   |         |            also borrowed as immutable, by `b`, here
-   |         first mutable borrow, by `a`, occurs here
+   |         |            |       value is mutably borrowed by `c` here
+   |         |            value is borrowed by `b` here
+   |         value is mutably borrowed by `a` here
 
 error: cannot borrow value as mutable because it is also borrowed as immutable
   --> $DIR/borrowck-pat-ref-mut-and-ref.rs:33:22
@@ -23,8 +23,8 @@ error: cannot borrow value as mutable because it is also borrowed as immutable
 LL |     let ref mut a @ (ref b @ ref mut c) = u(); // sub-in-sub
    |                      -----^^^---------
    |                      |       |
-   |                      |       mutable borrow, by `c`, occurs here
-   |                      immutable borrow, by `b`, occurs here
+   |                      |       value is mutably borrowed by `c` here
+   |                      value is borrowed by `b` here
 
 error: cannot borrow value as mutable because it is also borrowed as immutable
   --> $DIR/borrowck-pat-ref-mut-and-ref.rs:37:9
@@ -32,8 +32,8 @@ error: cannot borrow value as mutable because it is also borrowed as immutable
 LL |     let ref a @ ref mut b = U;
    |         -----^^^---------
    |         |       |
-   |         |       mutable borrow, by `b`, occurs here
-   |         immutable borrow, by `a`, occurs here
+   |         |       value is mutably borrowed by `b` here
+   |         value is borrowed by `a` here
 
 error: cannot borrow value as immutable because it is also borrowed as mutable
   --> $DIR/borrowck-pat-ref-mut-and-ref.rs:39:9
@@ -41,8 +41,8 @@ error: cannot borrow value as immutable because it is also borrowed as mutable
 LL |     let ref mut a @ ref b = U;
    |         ---------^^^-----
    |         |           |
-   |         |           immutable borrow, by `b`, occurs here
-   |         mutable borrow, by `a`, occurs here
+   |         |           value is borrowed by `b` here
+   |         value is mutably borrowed by `a` here
 
 error: cannot borrow value as mutable because it is also borrowed as immutable
   --> $DIR/borrowck-pat-ref-mut-and-ref.rs:41:9
@@ -50,9 +50,9 @@ error: cannot borrow value as mutable because it is also borrowed as immutable
 LL |     let ref a @ (ref mut b, ref mut c) = (U, U);
    |         -----^^^^---------^^---------^
    |         |        |          |
-   |         |        |          mutable borrow, by `c`, occurs here
-   |         |        mutable borrow, by `b`, occurs here
-   |         immutable borrow, by `a`, occurs here
+   |         |        |          value is mutably borrowed by `c` here
+   |         |        value is mutably borrowed by `b` here
+   |         value is borrowed by `a` here
 
 error: cannot borrow value as immutable because it is also borrowed as mutable
   --> $DIR/borrowck-pat-ref-mut-and-ref.rs:43:9
@@ -60,9 +60,9 @@ error: cannot borrow value as immutable because it is also borrowed as mutable
 LL |     let ref mut a @ (ref b, ref c) = (U, U);
    |         ---------^^^^-----^^-----^
    |         |            |      |
-   |         |            |      immutable borrow, by `c`, occurs here
-   |         |            immutable borrow, by `b`, occurs here
-   |         mutable borrow, by `a`, occurs here
+   |         |            |      value is borrowed by `c` here
+   |         |            value is borrowed by `b` here
+   |         value is mutably borrowed by `a` here
 
 error: cannot borrow value as immutable because it is also borrowed as mutable
   --> $DIR/borrowck-pat-ref-mut-and-ref.rs:46:9
@@ -70,8 +70,8 @@ error: cannot borrow value as immutable because it is also borrowed as mutable
 LL |     let ref mut a @ ref b = u();
    |         ---------^^^-----
    |         |           |
-   |         |           immutable borrow, by `b`, occurs here
-   |         mutable borrow, by `a`, occurs here
+   |         |           value is borrowed by `b` here
+   |         value is mutably borrowed by `a` here
 
 error: cannot borrow value as mutable because it is also borrowed as immutable
   --> $DIR/borrowck-pat-ref-mut-and-ref.rs:51:9
@@ -79,8 +79,8 @@ error: cannot borrow value as mutable because it is also borrowed as immutable
 LL |     let ref a @ ref mut b = u();
    |         -----^^^---------
    |         |       |
-   |         |       mutable borrow, by `b`, occurs here
-   |         immutable borrow, by `a`, occurs here
+   |         |       value is mutably borrowed by `b` here
+   |         value is borrowed by `a` here
 
 error: cannot borrow value as immutable because it is also borrowed as mutable
   --> $DIR/borrowck-pat-ref-mut-and-ref.rs:57:9
@@ -88,8 +88,8 @@ error: cannot borrow value as immutable because it is also borrowed as mutable
 LL |     let ref mut a @ ref b = U;
    |         ---------^^^-----
    |         |           |
-   |         |           immutable borrow, by `b`, occurs here
-   |         mutable borrow, by `a`, occurs here
+   |         |           value is borrowed by `b` here
+   |         value is mutably borrowed by `a` here
 
 error: cannot borrow value as mutable because it is also borrowed as immutable
   --> $DIR/borrowck-pat-ref-mut-and-ref.rs:61:9
@@ -97,8 +97,8 @@ error: cannot borrow value as mutable because it is also borrowed as immutable
 LL |     let ref a @ ref mut b = U;
    |         -----^^^---------
    |         |       |
-   |         |       mutable borrow, by `b`, occurs here
-   |         immutable borrow, by `a`, occurs here
+   |         |       value is mutably borrowed by `b` here
+   |         value is borrowed by `a` here
 
 error: cannot borrow value as immutable because it is also borrowed as mutable
   --> $DIR/borrowck-pat-ref-mut-and-ref.rs:67:9
@@ -106,8 +106,8 @@ error: cannot borrow value as immutable because it is also borrowed as mutable
 LL |         ref mut a @ Ok(ref b) | ref mut a @ Err(ref b) => {
    |         ---------^^^^^^-----^
    |         |              |
-   |         |              immutable borrow, by `b`, occurs here
-   |         mutable borrow, by `a`, occurs here
+   |         |              value is borrowed by `b` here
+   |         value is mutably borrowed by `a` here
 
 error: cannot borrow value as immutable because it is also borrowed as mutable
   --> $DIR/borrowck-pat-ref-mut-and-ref.rs:67:33
@@ -115,8 +115,8 @@ error: cannot borrow value as immutable because it is also borrowed as mutable
 LL |         ref mut a @ Ok(ref b) | ref mut a @ Err(ref b) => {
    |                                 ---------^^^^^^^-----^
    |                                 |               |
-   |                                 |               immutable borrow, by `b`, occurs here
-   |                                 mutable borrow, by `a`, occurs here
+   |                                 |               value is borrowed by `b` here
+   |                                 value is mutably borrowed by `a` here
 
 error: cannot borrow value as mutable because it is also borrowed as immutable
   --> $DIR/borrowck-pat-ref-mut-and-ref.rs:76:9
@@ -124,8 +124,8 @@ error: cannot borrow value as mutable because it is also borrowed as immutable
 LL |         ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) => {
    |         -----^^^^^^---------^
    |         |          |
-   |         |          mutable borrow, by `b`, occurs here
-   |         immutable borrow, by `a`, occurs here
+   |         |          value is mutably borrowed by `b` here
+   |         value is borrowed by `a` here
 
 error: cannot borrow value as mutable because it is also borrowed as immutable
   --> $DIR/borrowck-pat-ref-mut-and-ref.rs:76:33
@@ -133,8 +133,8 @@ error: cannot borrow value as mutable because it is also borrowed as immutable
 LL |         ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) => {
    |                                 -----^^^^^^^---------^
    |                                 |           |
-   |                                 |           mutable borrow, by `b`, occurs here
-   |                                 immutable borrow, by `a`, occurs here
+   |                                 |           value is mutably borrowed by `b` here
+   |                                 value is borrowed by `a` here
 
 error: cannot borrow value as mutable because it is also borrowed as immutable
   --> $DIR/borrowck-pat-ref-mut-and-ref.rs:87:9
@@ -142,8 +142,8 @@ error: cannot borrow value as mutable because it is also borrowed as immutable
 LL |         ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) if { *b = U; false } => {}
    |         -----^^^^^^---------^
    |         |          |
-   |         |          mutable borrow, by `b`, occurs here
-   |         immutable borrow, by `a`, occurs here
+   |         |          value is mutably borrowed by `b` here
+   |         value is borrowed by `a` here
 
 error: cannot borrow value as mutable because it is also borrowed as immutable
   --> $DIR/borrowck-pat-ref-mut-and-ref.rs:87:33
@@ -151,8 +151,8 @@ error: cannot borrow value as mutable because it is also borrowed as immutable
 LL |         ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) if { *b = U; false } => {}
    |                                 -----^^^^^^^---------^
    |                                 |           |
-   |                                 |           mutable borrow, by `b`, occurs here
-   |                                 immutable borrow, by `a`, occurs here
+   |                                 |           value is mutably borrowed by `b` here
+   |                                 value is borrowed by `a` here
 
 error: cannot borrow value as immutable because it is also borrowed as mutable
   --> $DIR/borrowck-pat-ref-mut-and-ref.rs:94:9
@@ -160,8 +160,8 @@ error: cannot borrow value as immutable because it is also borrowed as mutable
 LL |         ref mut a @ Ok(ref b) | ref mut a @ Err(ref b) if { *a = Err(U); false } => {}
    |         ---------^^^^^^-----^
    |         |              |
-   |         |              immutable borrow, by `b`, occurs here
-   |         mutable borrow, by `a`, occurs here
+   |         |              value is borrowed by `b` here
+   |         value is mutably borrowed by `a` here
 
 error: cannot borrow value as immutable because it is also borrowed as mutable
   --> $DIR/borrowck-pat-ref-mut-and-ref.rs:94:33
@@ -169,8 +169,8 @@ error: cannot borrow value as immutable because it is also borrowed as mutable
 LL |         ref mut a @ Ok(ref b) | ref mut a @ Err(ref b) if { *a = Err(U); false } => {}
    |                                 ---------^^^^^^^-----^
    |                                 |               |
-   |                                 |               immutable borrow, by `b`, occurs here
-   |                                 mutable borrow, by `a`, occurs here
+   |                                 |               value is borrowed by `b` here
+   |                                 value is mutably borrowed by `a` here
 
 error: cannot borrow value as mutable because it is also borrowed as immutable
   --> $DIR/borrowck-pat-ref-mut-and-ref.rs:101:9
@@ -178,8 +178,8 @@ error: cannot borrow value as mutable because it is also borrowed as immutable
 LL |         ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) if { drop(b); false } => {}
    |         -----^^^^^^---------^
    |         |          |
-   |         |          mutable borrow, by `b`, occurs here
-   |         immutable borrow, by `a`, occurs here
+   |         |          value is mutably borrowed by `b` here
+   |         value is borrowed by `a` here
 
 error: cannot borrow value as mutable because it is also borrowed as immutable
   --> $DIR/borrowck-pat-ref-mut-and-ref.rs:101:33
@@ -187,8 +187,8 @@ error: cannot borrow value as mutable because it is also borrowed as immutable
 LL |         ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) if { drop(b); false } => {}
    |                                 -----^^^^^^^---------^
    |                                 |           |
-   |                                 |           mutable borrow, by `b`, occurs here
-   |                                 immutable borrow, by `a`, occurs here
+   |                                 |           value is mutably borrowed by `b` here
+   |                                 value is borrowed by `a` here
 
 error: cannot borrow value as immutable because it is also borrowed as mutable
   --> $DIR/borrowck-pat-ref-mut-and-ref.rs:109:9
@@ -196,8 +196,8 @@ error: cannot borrow value as immutable because it is also borrowed as mutable
 LL |         ref mut a @ Ok(ref b) | ref mut a @ Err(ref b) if { drop(a); false } => {}
    |         ---------^^^^^^-----^
    |         |              |
-   |         |              immutable borrow, by `b`, occurs here
-   |         mutable borrow, by `a`, occurs here
+   |         |              value is borrowed by `b` here
+   |         value is mutably borrowed by `a` here
 
 error: cannot borrow value as immutable because it is also borrowed as mutable
   --> $DIR/borrowck-pat-ref-mut-and-ref.rs:109:33
@@ -205,8 +205,8 @@ error: cannot borrow value as immutable because it is also borrowed as mutable
 LL |         ref mut a @ Ok(ref b) | ref mut a @ Err(ref b) if { drop(a); false } => {}
    |                                 ---------^^^^^^^-----^
    |                                 |               |
-   |                                 |               immutable borrow, by `b`, occurs here
-   |                                 mutable borrow, by `a`, occurs here
+   |                                 |               value is borrowed by `b` here
+   |                                 value is mutably borrowed by `a` here
 
 error: cannot borrow value as mutable because it is also borrowed as immutable
   --> $DIR/borrowck-pat-ref-mut-and-ref.rs:117:9
@@ -214,9 +214,9 @@ error: cannot borrow value as mutable because it is also borrowed as immutable
 LL |     let ref a @ (ref mut b, ref mut c) = (U, U);
    |         -----^^^^---------^^---------^
    |         |        |          |
-   |         |        |          mutable borrow, by `c`, occurs here
-   |         |        mutable borrow, by `b`, occurs here
-   |         immutable borrow, by `a`, occurs here
+   |         |        |          value is mutably borrowed by `c` here
+   |         |        value is mutably borrowed by `b` here
+   |         value is borrowed by `a` here
 
 error: cannot borrow value as mutable because it is also borrowed as immutable
   --> $DIR/borrowck-pat-ref-mut-and-ref.rs:123:9
@@ -224,9 +224,9 @@ error: cannot borrow value as mutable because it is also borrowed as immutable
 LL |     let ref a @ (ref mut b, ref mut c) = (U, U);
    |         -----^^^^---------^^---------^
    |         |        |          |
-   |         |        |          mutable borrow, by `c`, occurs here
-   |         |        mutable borrow, by `b`, occurs here
-   |         immutable borrow, by `a`, occurs here
+   |         |        |          value is mutably borrowed by `c` here
+   |         |        value is mutably borrowed by `b` here
+   |         value is borrowed by `a` here
 
 error: cannot borrow value as mutable because it is also borrowed as immutable
   --> $DIR/borrowck-pat-ref-mut-and-ref.rs:129:9
@@ -234,9 +234,9 @@ error: cannot borrow value as mutable because it is also borrowed as immutable
 LL |     let ref a @ (ref mut b, ref mut c) = (U, U);
    |         -----^^^^---------^^---------^
    |         |        |          |
-   |         |        |          mutable borrow, by `c`, occurs here
-   |         |        mutable borrow, by `b`, occurs here
-   |         immutable borrow, by `a`, occurs here
+   |         |        |          value is mutably borrowed by `c` here
+   |         |        value is mutably borrowed by `b` here
+   |         value is borrowed by `a` here
 
 error: cannot borrow value as immutable because it is also borrowed as mutable
   --> $DIR/borrowck-pat-ref-mut-and-ref.rs:134:9
@@ -244,9 +244,9 @@ error: cannot borrow value as immutable because it is also borrowed as mutable
 LL |     let ref mut a @ (ref b, ref c) = (U, U);
    |         ---------^^^^-----^^-----^
    |         |            |      |
-   |         |            |      immutable borrow, by `c`, occurs here
-   |         |            immutable borrow, by `b`, occurs here
-   |         mutable borrow, by `a`, occurs here
+   |         |            |      value is borrowed by `c` here
+   |         |            value is borrowed by `b` here
+   |         value is mutably borrowed by `a` here
 
 error: cannot borrow value as mutable because it is also borrowed as immutable
   --> $DIR/borrowck-pat-ref-mut-and-ref.rs:22:11
@@ -254,8 +254,8 @@ error: cannot borrow value as mutable because it is also borrowed as immutable
 LL |     fn f1(ref a @ ref mut b: U) {}
    |           -----^^^---------
    |           |       |
-   |           |       mutable borrow, by `b`, occurs here
-   |           immutable borrow, by `a`, occurs here
+   |           |       value is mutably borrowed by `b` here
+   |           value is borrowed by `a` here
 
 error: cannot borrow value as immutable because it is also borrowed as mutable
   --> $DIR/borrowck-pat-ref-mut-and-ref.rs:24:11
@@ -263,8 +263,8 @@ error: cannot borrow value as immutable because it is also borrowed as mutable
 LL |     fn f2(ref mut a @ ref b: U) {}
    |           ---------^^^-----
    |           |           |
-   |           |           immutable borrow, by `b`, occurs here
-   |           mutable borrow, by `a`, occurs here
+   |           |           value is borrowed by `b` here
+   |           value is mutably borrowed by `a` here
 
 error: cannot borrow value as mutable because it is also borrowed as immutable
   --> $DIR/borrowck-pat-ref-mut-and-ref.rs:26:11
@@ -272,8 +272,8 @@ error: cannot borrow value as mutable because it is also borrowed as immutable
 LL |     fn f3(ref a @ [ref b, ref mut mid @ .., ref c]: [U; 4]) {}
    |           -----^^^^^^^^^^^----------------^^^^^^^^
    |           |               |
-   |           |               mutable borrow, by `mid`, occurs here
-   |           immutable borrow, by `a`, occurs here
+   |           |               value is mutably borrowed by `mid` here
+   |           value is borrowed by `a` here
 
 error: cannot borrow value as mutable because it is also borrowed as immutable
   --> $DIR/borrowck-pat-ref-mut-and-ref.rs:28:22
@@ -281,9 +281,9 @@ error: cannot borrow value as mutable because it is also borrowed as immutable
 LL |     fn f4_also_moved(ref a @ ref mut b @ c: U) {}
    |                      -----^^^-------------
    |                      |       |           |
-   |                      |       |           also moved into `c` here
-   |                      |       mutable borrow, by `b`, occurs here
-   |                      immutable borrow, by `a`, occurs here
+   |                      |       |           value is moved into `c` here
+   |                      |       value is mutably borrowed by `b` here
+   |                      value is borrowed by `a` here
 
 error: cannot move out of value because it is borrowed
   --> $DIR/borrowck-pat-ref-mut-and-ref.rs:28:30
@@ -291,8 +291,8 @@ error: cannot move out of value because it is borrowed
 LL |     fn f4_also_moved(ref a @ ref mut b @ c: U) {}
    |                              ---------^^^-
    |                              |           |
-   |                              |           value moved into `c` here
-   |                              value borrowed, by `b`, here
+   |                              |           value is moved into `c` here
+   |                              value is mutably borrowed by `b` here
 
 error[E0502]: cannot borrow value as immutable because it is also borrowed as mutable
   --> $DIR/borrowck-pat-ref-mut-and-ref.rs:8:31
index ad4ce7952ca7494b065b86b9f62107b24655d5ea..a0cb04a064e06dd05796771dedeafd28b6cea917 100644 (file)
@@ -4,8 +4,8 @@ error: cannot borrow value as mutable more than once at a time
 LL |     let ref mut a @ ref mut b = U;
    |         ---------^^^---------
    |         |           |
-   |         |           another mutable borrow, by `b`, occurs here
-   |         first mutable borrow, by `a`, occurs here
+   |         |           value is mutably borrowed by `b` here
+   |         value is mutably borrowed by `a` here
 
 error: cannot borrow value as mutable more than once at a time
   --> $DIR/borrowck-pat-ref-mut-twice.rs:29:9
@@ -13,8 +13,8 @@ error: cannot borrow value as mutable more than once at a time
 LL |     let ref mut a @ ref mut b = U;
    |         ---------^^^---------
    |         |           |
-   |         |           another mutable borrow, by `b`, occurs here
-   |         first mutable borrow, by `a`, occurs here
+   |         |           value is mutably borrowed by `b` here
+   |         value is mutably borrowed by `a` here
 
 error: cannot borrow value as mutable more than once at a time
   --> $DIR/borrowck-pat-ref-mut-twice.rs:33:9
@@ -22,8 +22,8 @@ error: cannot borrow value as mutable more than once at a time
 LL |     let ref mut a @ ref mut b = U;
    |         ---------^^^---------
    |         |           |
-   |         |           another mutable borrow, by `b`, occurs here
-   |         first mutable borrow, by `a`, occurs here
+   |         |           value is mutably borrowed by `b` here
+   |         value is mutably borrowed by `a` here
 
 error: cannot borrow value as mutable more than once at a time
   --> $DIR/borrowck-pat-ref-mut-twice.rs:36:9
@@ -31,8 +31,8 @@ error: cannot borrow value as mutable more than once at a time
 LL |     let ref mut a @ ref mut b = U;
    |         ---------^^^---------
    |         |           |
-   |         |           another mutable borrow, by `b`, occurs here
-   |         first mutable borrow, by `a`, occurs here
+   |         |           value is mutably borrowed by `b` here
+   |         value is mutably borrowed by `a` here
 
 error: cannot borrow value as mutable more than once at a time
   --> $DIR/borrowck-pat-ref-mut-twice.rs:39:9
@@ -40,8 +40,8 @@ error: cannot borrow value as mutable more than once at a time
 LL |     let ref mut a @ ref mut b = U;
    |         ---------^^^---------
    |         |           |
-   |         |           another mutable borrow, by `b`, occurs here
-   |         first mutable borrow, by `a`, occurs here
+   |         |           value is mutably borrowed by `b` here
+   |         value is mutably borrowed by `a` here
 
 error: cannot borrow value as mutable more than once at a time
   --> $DIR/borrowck-pat-ref-mut-twice.rs:44:9
@@ -49,18 +49,18 @@ error: cannot borrow value as mutable more than once at a time
 LL |       let ref mut a @ (
    |           ^--------
    |           |
-   |  _________first mutable borrow, by `a`, occurs here
+   |  _________value is mutably borrowed by `a` here
    | |
 LL | |
 LL | |         ref mut b,
-   | |         --------- another mutable borrow, by `b`, occurs here
+   | |         --------- value is mutably borrowed by `b` here
 LL | |         [
 LL | |             ref mut c,
-   | |             --------- another mutable borrow, by `c`, occurs here
+   | |             --------- value is mutably borrowed by `c` here
 LL | |             ref mut d,
-   | |             --------- another mutable borrow, by `d`, occurs here
+   | |             --------- value is mutably borrowed by `d` here
 LL | |             ref e,
-   | |             ----- also borrowed as immutable, by `e`, here
+   | |             ----- value is borrowed by `e` here
 LL | |         ]
 LL | |     ) = (U, [U, U, U]);
    | |_____^
@@ -71,18 +71,18 @@ error: cannot borrow value as mutable more than once at a time
 LL |       let ref mut a @ (
    |           ^--------
    |           |
-   |  _________first mutable borrow, by `a`, occurs here
+   |  _________value is mutably borrowed by `a` here
    | |
 LL | |
 LL | |             ref mut b,
-   | |             --------- another mutable borrow, by `b`, occurs here
+   | |             --------- value is mutably borrowed by `b` here
 LL | |             [
 LL | |                 ref mut c,
-   | |                 --------- another mutable borrow, by `c`, occurs here
+   | |                 --------- value is mutably borrowed by `c` here
 LL | |                 ref mut d,
-   | |                 --------- another mutable borrow, by `d`, occurs here
+   | |                 --------- value is mutably borrowed by `d` here
 LL | |                 ref e,
-   | |                 ----- also borrowed as immutable, by `e`, here
+   | |                 ----- value is borrowed by `e` here
 LL | |             ]
 LL | |         ) = (u(), [u(), u(), u()]);
    | |_________^
@@ -157,8 +157,8 @@ error: cannot borrow value as mutable more than once at a time
 LL |         ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => {
    |         ---------^^^^^^---------^
    |         |              |
-   |         |              another mutable borrow, by `b`, occurs here
-   |         first mutable borrow, by `a`, occurs here
+   |         |              value is mutably borrowed by `b` here
+   |         value is mutably borrowed by `a` here
 
 error: cannot borrow value as mutable more than once at a time
   --> $DIR/borrowck-pat-ref-mut-twice.rs:76:37
@@ -166,8 +166,8 @@ error: cannot borrow value as mutable more than once at a time
 LL |         ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => {
    |                                     ---------^^^^^^^---------^
    |                                     |               |
-   |                                     |               another mutable borrow, by `b`, occurs here
-   |                                     first mutable borrow, by `a`, occurs here
+   |                                     |               value is mutably borrowed by `b` here
+   |                                     value is mutably borrowed by `a` here
 
 error: cannot borrow value as mutable more than once at a time
   --> $DIR/borrowck-pat-ref-mut-twice.rs:82:9
@@ -175,8 +175,8 @@ error: cannot borrow value as mutable more than once at a time
 LL |         ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => {
    |         ---------^^^^^^---------^
    |         |              |
-   |         |              another mutable borrow, by `b`, occurs here
-   |         first mutable borrow, by `a`, occurs here
+   |         |              value is mutably borrowed by `b` here
+   |         value is mutably borrowed by `a` here
 
 error: cannot borrow value as mutable more than once at a time
   --> $DIR/borrowck-pat-ref-mut-twice.rs:82:37
@@ -184,8 +184,8 @@ error: cannot borrow value as mutable more than once at a time
 LL |         ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => {
    |                                     ---------^^^^^^^---------^
    |                                     |               |
-   |                                     |               another mutable borrow, by `b`, occurs here
-   |                                     first mutable borrow, by `a`, occurs here
+   |                                     |               value is mutably borrowed by `b` here
+   |                                     value is mutably borrowed by `a` here
 
 error: cannot borrow value as mutable more than once at a time
   --> $DIR/borrowck-pat-ref-mut-twice.rs:89:9
@@ -193,8 +193,8 @@ error: cannot borrow value as mutable more than once at a time
 LL |         ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => {
    |         ---------^^^^^^---------^
    |         |              |
-   |         |              another mutable borrow, by `b`, occurs here
-   |         first mutable borrow, by `a`, occurs here
+   |         |              value is mutably borrowed by `b` here
+   |         value is mutably borrowed by `a` here
 
 error: cannot borrow value as mutable more than once at a time
   --> $DIR/borrowck-pat-ref-mut-twice.rs:89:37
@@ -202,8 +202,8 @@ error: cannot borrow value as mutable more than once at a time
 LL |         ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => {
    |                                     ---------^^^^^^^---------^
    |                                     |               |
-   |                                     |               another mutable borrow, by `b`, occurs here
-   |                                     first mutable borrow, by `a`, occurs here
+   |                                     |               value is mutably borrowed by `b` here
+   |                                     value is mutably borrowed by `a` here
 
 error: cannot borrow value as mutable more than once at a time
   --> $DIR/borrowck-pat-ref-mut-twice.rs:101:9
@@ -211,8 +211,8 @@ error: cannot borrow value as mutable more than once at a time
 LL |         ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => {
    |         ---------^^^^^^---------^
    |         |              |
-   |         |              another mutable borrow, by `b`, occurs here
-   |         first mutable borrow, by `a`, occurs here
+   |         |              value is mutably borrowed by `b` here
+   |         value is mutably borrowed by `a` here
 
 error: cannot borrow value as mutable more than once at a time
   --> $DIR/borrowck-pat-ref-mut-twice.rs:101:37
@@ -220,8 +220,8 @@ error: cannot borrow value as mutable more than once at a time
 LL |         ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => {
    |                                     ---------^^^^^^^---------^
    |                                     |               |
-   |                                     |               another mutable borrow, by `b`, occurs here
-   |                                     first mutable borrow, by `a`, occurs here
+   |                                     |               value is mutably borrowed by `b` here
+   |                                     value is mutably borrowed by `a` here
 
 error: cannot borrow value as mutable more than once at a time
   --> $DIR/borrowck-pat-ref-mut-twice.rs:8:11
@@ -229,8 +229,8 @@ error: cannot borrow value as mutable more than once at a time
 LL |     fn f1(ref mut a @ ref mut b: U) {}
    |           ---------^^^---------
    |           |           |
-   |           |           another mutable borrow, by `b`, occurs here
-   |           first mutable borrow, by `a`, occurs here
+   |           |           value is mutably borrowed by `b` here
+   |           value is mutably borrowed by `a` here
 
 error: cannot borrow value as mutable more than once at a time
   --> $DIR/borrowck-pat-ref-mut-twice.rs:10:11
@@ -238,8 +238,8 @@ error: cannot borrow value as mutable more than once at a time
 LL |     fn f2(ref mut a @ ref mut b: U) {}
    |           ---------^^^---------
    |           |           |
-   |           |           another mutable borrow, by `b`, occurs here
-   |           first mutable borrow, by `a`, occurs here
+   |           |           value is mutably borrowed by `b` here
+   |           value is mutably borrowed by `a` here
 
 error: cannot borrow value as mutable more than once at a time
   --> $DIR/borrowck-pat-ref-mut-twice.rs:13:9
@@ -247,13 +247,13 @@ error: cannot borrow value as mutable more than once at a time
 LL |           ref mut a @ [
    |           ^--------
    |           |
-   |  _________first mutable borrow, by `a`, occurs here
+   |  _________value is mutably borrowed by `a` here
    | |
 LL | |
 LL | |             [ref b @ .., _],
-   | |              ---------- also borrowed as immutable, by `b`, here
+   | |              ---------- value is borrowed by `b` here
 LL | |             [_, ref mut mid @ ..],
-   | |                 ---------------- another mutable borrow, by `mid`, occurs here
+   | |                 ---------------- value is mutably borrowed by `mid` here
 LL | |             ..,
 LL | |             [..],
 LL | |         ] : [[U; 4]; 5]
@@ -265,9 +265,9 @@ error: cannot borrow value as mutable more than once at a time
 LL |     fn f4_also_moved(ref mut a @ ref mut b @ c: U) {}
    |                      ---------^^^-------------
    |                      |           |           |
-   |                      |           |           also moved into `c` here
-   |                      |           another mutable borrow, by `b`, occurs here
-   |                      first mutable borrow, by `a`, occurs here
+   |                      |           |           value is moved into `c` here
+   |                      |           value is mutably borrowed by `b` here
+   |                      value is mutably borrowed by `a` here
 
 error: cannot move out of value because it is borrowed
   --> $DIR/borrowck-pat-ref-mut-twice.rs:21:34
@@ -275,8 +275,8 @@ error: cannot move out of value because it is borrowed
 LL |     fn f4_also_moved(ref mut a @ ref mut b @ c: U) {}
    |                                  ---------^^^-
    |                                  |           |
-   |                                  |           value moved into `c` here
-   |                                  value borrowed, by `b`, here
+   |                                  |           value is moved into `c` here
+   |                                  value is mutably borrowed by `b` here
 
 error[E0499]: cannot borrow value as mutable more than once at a time
   --> $DIR/borrowck-pat-ref-mut-twice.rs:29:9
index 638bdd6db7606761b035dfea6375a9b9761c5487..73ebbf48118daebf4cdd798f82374b856a949f5a 100644 (file)
@@ -4,8 +4,8 @@ error: cannot move out of value because it is borrowed
 LL |     let ref a @ b = NotCopy;
    |         -----^^^-
    |         |       |
-   |         |       value moved into `b` here
-   |         value borrowed, by `a`, here
+   |         |       value is moved into `b` here
+   |         value is borrowed by `a` here
 
 error: cannot move out of value because it is borrowed
   --> $DIR/default-binding-modes-both-sides-independent.rs:29:9
@@ -13,8 +13,8 @@ error: cannot move out of value because it is borrowed
 LL |     let ref mut a @ b = NotCopy;
    |         ---------^^^-
    |         |           |
-   |         |           value moved into `b` here
-   |         value borrowed, by `a`, here
+   |         |           value is moved into `b` here
+   |         value is mutably borrowed by `a` here
 
 error: cannot move out of value because it is borrowed
   --> $DIR/default-binding-modes-both-sides-independent.rs:34:12
@@ -22,8 +22,8 @@ error: cannot move out of value because it is borrowed
 LL |         Ok(ref a @ b) | Err(b @ ref a) => {
    |            -----^^^-
    |            |       |
-   |            |       value moved into `b` here
-   |            value borrowed, by `a`, here
+   |            |       value is moved into `b` here
+   |            value is borrowed by `a` here
 
 error: borrow of moved value
   --> $DIR/default-binding-modes-both-sides-independent.rs:34:29
@@ -46,8 +46,8 @@ error: cannot move out of value because it is borrowed
 LL |         ref a @ b => {
    |         -----^^^-
    |         |       |
-   |         |       value moved into `b` here
-   |         value borrowed, by `a`, here
+   |         |       value is moved into `b` here
+   |         value is borrowed by `a` here
 
 error[E0382]: borrow of moved value
   --> $DIR/default-binding-modes-both-sides-independent.rs:29:9
index 1b93267b397714cf694a084d0b7a3da0100c90dd..c7c7c074f7cd0f07ae76257f0066b53bfcdddd24 100644 (file)
@@ -1,6 +1,8 @@
 error[E0505]: cannot move out of `arr[..]` because it is borrowed
   --> $DIR/borrowck-move-ref-pattern.rs:8:24
    |
+LL |     let mut arr = [U, U, U, U, U];
+   |         ------- binding `arr` declared here
 LL |     let hold_all = &arr;
    |                    ---- borrow of `arr` occurs here
 LL |     let [ref _x0_hold, _x1, ref xs_hold @ ..] = arr;
diff --git a/tests/ui/proc-macro/allowed-signatures.rs b/tests/ui/proc-macro/allowed-signatures.rs
new file mode 100644 (file)
index 0000000..8685087
--- /dev/null
@@ -0,0 +1,26 @@
+// check-pass
+// force-host
+// no-prefer-dynamic
+
+#![crate_type = "proc-macro"]
+#![allow(private_in_public)]
+extern crate proc_macro;
+use proc_macro::TokenStream;
+
+#[proc_macro]
+pub fn foo<T>(t: T) -> TokenStream {
+  TokenStream::new()
+}
+
+trait Project {
+    type Assoc;
+}
+
+impl Project for () {
+    type Assoc = TokenStream;
+}
+
+#[proc_macro]
+pub fn uwu(_input: <() as Project>::Assoc) -> <() as Project>::Assoc {
+    TokenStream::new()
+}
diff --git a/tests/ui/proc-macro/proc-macro-abi.rs b/tests/ui/proc-macro/proc-macro-abi.rs
new file mode 100644 (file)
index 0000000..873660a
--- /dev/null
@@ -0,0 +1,31 @@
+// force-host
+// no-prefer-dynamic
+
+#![crate_type = "proc-macro"]
+#![allow(warnings)]
+
+extern crate proc_macro;
+use proc_macro::TokenStream;
+
+#[proc_macro]
+pub extern "C" fn abi(a: TokenStream) -> TokenStream {
+    //~^ ERROR proc macro functions may not be `extern "C"`
+    a
+}
+
+#[proc_macro]
+pub extern "system" fn abi2(a: TokenStream) -> TokenStream {
+    //~^ ERROR proc macro functions may not be `extern "system"`
+    a
+}
+
+#[proc_macro]
+pub extern fn abi3(a: TokenStream) -> TokenStream {
+    //~^ ERROR proc macro functions may not be `extern "C"`
+    a
+}
+
+#[proc_macro]
+pub extern "Rust" fn abi4(a: TokenStream) -> TokenStream {
+    a
+}
diff --git a/tests/ui/proc-macro/proc-macro-abi.stderr b/tests/ui/proc-macro/proc-macro-abi.stderr
new file mode 100644 (file)
index 0000000..9a781be
--- /dev/null
@@ -0,0 +1,20 @@
+error: proc macro functions may not be `extern "C"`
+  --> $DIR/proc-macro-abi.rs:11:1
+   |
+LL | pub extern "C" fn abi(a: TokenStream) -> TokenStream {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: proc macro functions may not be `extern "system"`
+  --> $DIR/proc-macro-abi.rs:17:1
+   |
+LL | pub extern "system" fn abi2(a: TokenStream) -> TokenStream {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: proc macro functions may not be `extern "C"`
+  --> $DIR/proc-macro-abi.rs:23:1
+   |
+LL | pub extern fn abi3(a: TokenStream) -> TokenStream {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 3 previous errors
+
diff --git a/tests/ui/proc-macro/signature-proc-macro-attribute.rs b/tests/ui/proc-macro/signature-proc-macro-attribute.rs
new file mode 100644 (file)
index 0000000..51abc8e
--- /dev/null
@@ -0,0 +1,32 @@
+// force-host
+// no-prefer-dynamic
+
+#![crate_type = "proc-macro"]
+
+extern crate proc_macro;
+use proc_macro::TokenStream;
+
+#[proc_macro_attribute]
+pub fn bad_input(input: String) -> TokenStream {
+    //~^ ERROR mismatched attribute proc macro signature
+    ::proc_macro::TokenStream::new()
+}
+
+#[proc_macro_attribute]
+pub fn bad_output(input: TokenStream) -> String {
+    //~^ ERROR mismatched attribute proc macro signature
+    //~| ERROR mismatched attribute proc macro signature
+    String::from("blah")
+}
+
+#[proc_macro_attribute]
+pub fn bad_everything(input: String) -> String {
+    //~^ ERROR mismatched attribute proc macro signature
+    //~| ERROR mismatched attribute proc macro signature
+    input
+}
+
+#[proc_macro_attribute]
+pub fn too_many(a: TokenStream, b: TokenStream, c: String) -> TokenStream {
+    //~^ ERROR mismatched attribute proc macro signature
+}
diff --git a/tests/ui/proc-macro/signature-proc-macro-attribute.stderr b/tests/ui/proc-macro/signature-proc-macro-attribute.stderr
new file mode 100644 (file)
index 0000000..abf7a6f
--- /dev/null
@@ -0,0 +1,42 @@
+error: mismatched attribute proc macro signature
+  --> $DIR/signature-proc-macro-attribute.rs:10:1
+   |
+LL | pub fn bad_input(input: String) -> TokenStream {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ attribute proc macro must have two arguments of type `proc_macro::TokenStream`
+
+error: mismatched attribute proc macro signature
+  --> $DIR/signature-proc-macro-attribute.rs:16:42
+   |
+LL | pub fn bad_output(input: TokenStream) -> String {
+   |                                          ^^^^^^ found std::string::String, expected type `proc_macro::TokenStream`
+   |
+   = note: attribute proc macros must have a signature of `fn(TokenStream, TokenStream) -> TokenStream`
+
+error: mismatched attribute proc macro signature
+  --> $DIR/signature-proc-macro-attribute.rs:16:1
+   |
+LL | pub fn bad_output(input: TokenStream) -> String {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ attribute proc macro must have two arguments of type `proc_macro::TokenStream`
+
+error: mismatched attribute proc macro signature
+  --> $DIR/signature-proc-macro-attribute.rs:23:41
+   |
+LL | pub fn bad_everything(input: String) -> String {
+   |                                         ^^^^^^ found std::string::String, expected type `proc_macro::TokenStream`
+   |
+   = note: attribute proc macros must have a signature of `fn(TokenStream, TokenStream) -> TokenStream`
+
+error: mismatched attribute proc macro signature
+  --> $DIR/signature-proc-macro-attribute.rs:23:1
+   |
+LL | pub fn bad_everything(input: String) -> String {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ attribute proc macro must have two arguments of type `proc_macro::TokenStream`
+
+error: mismatched attribute proc macro signature
+  --> $DIR/signature-proc-macro-attribute.rs:30:49
+   |
+LL | pub fn too_many(a: TokenStream, b: TokenStream, c: String) -> TokenStream {
+   |                                                 ^^^^^^^^^ found unexpected argument
+
+error: aborting due to 6 previous errors
+
diff --git a/tests/ui/proc-macro/signature-proc-macro-derive.rs b/tests/ui/proc-macro/signature-proc-macro-derive.rs
new file mode 100644 (file)
index 0000000..f2fd824
--- /dev/null
@@ -0,0 +1,31 @@
+// force-host
+// no-prefer-dynamic
+
+#![crate_type = "proc-macro"]
+
+extern crate proc_macro;
+use proc_macro::TokenStream;
+
+#[proc_macro_derive(Blah)]
+pub fn bad_input(input: String) -> TokenStream {
+    //~^ ERROR mismatched derive proc macro signature
+    TokenStream::new()
+}
+
+#[proc_macro_derive(Bleh)]
+pub fn bad_output(input: TokenStream) -> String {
+    //~^ ERROR mismatched derive proc macro signature
+    String::from("blah")
+}
+
+#[proc_macro_derive(Bluh)]
+pub fn bad_everything(input: String) -> String {
+    //~^ ERROR mismatched derive proc macro signature
+    //~| ERROR mismatched derive proc macro signature
+    input
+}
+
+#[proc_macro_derive(Blih)]
+pub fn too_many(a: TokenStream, b: TokenStream, c: String) -> TokenStream {
+    //~^ ERROR mismatched derive proc macro signature
+}
diff --git a/tests/ui/proc-macro/signature-proc-macro-derive.stderr b/tests/ui/proc-macro/signature-proc-macro-derive.stderr
new file mode 100644 (file)
index 0000000..a358ae2
--- /dev/null
@@ -0,0 +1,40 @@
+error: mismatched derive proc macro signature
+  --> $DIR/signature-proc-macro-derive.rs:10:25
+   |
+LL | pub fn bad_input(input: String) -> TokenStream {
+   |                         ^^^^^^ found std::string::String, expected type `proc_macro::TokenStream`
+   |
+   = note: derive proc macros must have a signature of `fn(TokenStream) -> TokenStream`
+
+error: mismatched derive proc macro signature
+  --> $DIR/signature-proc-macro-derive.rs:16:42
+   |
+LL | pub fn bad_output(input: TokenStream) -> String {
+   |                                          ^^^^^^ found std::string::String, expected type `proc_macro::TokenStream`
+   |
+   = note: derive proc macros must have a signature of `fn(TokenStream) -> TokenStream`
+
+error: mismatched derive proc macro signature
+  --> $DIR/signature-proc-macro-derive.rs:22:41
+   |
+LL | pub fn bad_everything(input: String) -> String {
+   |                                         ^^^^^^ found std::string::String, expected type `proc_macro::TokenStream`
+   |
+   = note: derive proc macros must have a signature of `fn(TokenStream) -> TokenStream`
+
+error: mismatched derive proc macro signature
+  --> $DIR/signature-proc-macro-derive.rs:22:30
+   |
+LL | pub fn bad_everything(input: String) -> String {
+   |                              ^^^^^^ found std::string::String, expected type `proc_macro::TokenStream`
+   |
+   = note: derive proc macros must have a signature of `fn(TokenStream) -> TokenStream`
+
+error: mismatched derive proc macro signature
+  --> $DIR/signature-proc-macro-derive.rs:29:33
+   |
+LL | pub fn too_many(a: TokenStream, b: TokenStream, c: String) -> TokenStream {
+   |                                 ^^^^^^^^^^^^^^^^^^^^^^^^^ found unexpected arguments
+
+error: aborting due to 5 previous errors
+
diff --git a/tests/ui/proc-macro/signature-proc-macro.rs b/tests/ui/proc-macro/signature-proc-macro.rs
new file mode 100644 (file)
index 0000000..54770aa
--- /dev/null
@@ -0,0 +1,31 @@
+// force-host
+// no-prefer-dynamic
+
+#![crate_type = "proc-macro"]
+
+extern crate proc_macro;
+use proc_macro::TokenStream;
+
+#[proc_macro]
+pub fn bad_input(input: String) -> TokenStream {
+    //~^ ERROR mismatched function-like proc macro signature
+    ::proc_macro::TokenStream::new()
+}
+
+#[proc_macro]
+pub fn bad_output(input: TokenStream) -> String {
+    //~^ ERROR mismatched function-like proc macro signature
+    String::from("blah")
+}
+
+#[proc_macro]
+pub fn bad_everything(input: String) -> String {
+    //~^ ERROR mismatched function-like proc macro signature
+    //~| ERROR mismatched function-like proc macro signature
+    input
+}
+
+#[proc_macro]
+pub fn too_many(a: TokenStream, b: TokenStream, c: String) -> TokenStream {
+    //~^ ERROR mismatched function-like proc macro signature
+}
diff --git a/tests/ui/proc-macro/signature-proc-macro.stderr b/tests/ui/proc-macro/signature-proc-macro.stderr
new file mode 100644 (file)
index 0000000..4b14a54
--- /dev/null
@@ -0,0 +1,40 @@
+error: mismatched function-like proc macro signature
+  --> $DIR/signature-proc-macro.rs:10:25
+   |
+LL | pub fn bad_input(input: String) -> TokenStream {
+   |                         ^^^^^^ found std::string::String, expected type `proc_macro::TokenStream`
+   |
+   = note: function-like proc macros must have a signature of `fn(TokenStream) -> TokenStream`
+
+error: mismatched function-like proc macro signature
+  --> $DIR/signature-proc-macro.rs:16:42
+   |
+LL | pub fn bad_output(input: TokenStream) -> String {
+   |                                          ^^^^^^ found std::string::String, expected type `proc_macro::TokenStream`
+   |
+   = note: function-like proc macros must have a signature of `fn(TokenStream) -> TokenStream`
+
+error: mismatched function-like proc macro signature
+  --> $DIR/signature-proc-macro.rs:22:41
+   |
+LL | pub fn bad_everything(input: String) -> String {
+   |                                         ^^^^^^ found std::string::String, expected type `proc_macro::TokenStream`
+   |
+   = note: function-like proc macros must have a signature of `fn(TokenStream) -> TokenStream`
+
+error: mismatched function-like proc macro signature
+  --> $DIR/signature-proc-macro.rs:22:30
+   |
+LL | pub fn bad_everything(input: String) -> String {
+   |                              ^^^^^^ found std::string::String, expected type `proc_macro::TokenStream`
+   |
+   = note: function-like proc macros must have a signature of `fn(TokenStream) -> TokenStream`
+
+error: mismatched function-like proc macro signature
+  --> $DIR/signature-proc-macro.rs:29:33
+   |
+LL | pub fn too_many(a: TokenStream, b: TokenStream, c: String) -> TokenStream {
+   |                                 ^^^^^^^^^^^^^^^^^^^^^^^^^ found unexpected arguments
+
+error: aborting due to 5 previous errors
+
index 2302238253e82e172cf2a6ab068a2b5bdbdb3643..11187aa31bd8071c6047c1568bf7ac7373bbc30b 100644 (file)
@@ -8,6 +8,10 @@
 
 #[proc_macro_derive(A)]
 pub unsafe extern "C" fn foo(a: i32, b: u32) -> u32 {
-    //~^ ERROR: expected a `Fn<(proc_macro::TokenStream,)>` closure, found `unsafe extern "C" fn
+    //~^ ERROR: mismatched derive proc macro signature
+    //~| mismatched derive proc macro signature
+    //~| mismatched derive proc macro signature
+    //~| proc macro functions may not be `extern
+    //~| proc macro functions may not be `unsafe
     loop {}
 }
index 79f2001da005510f915eb3f696d550df0364f3c8..3dbe3f22a0df89310dbcb24e8fdb51e021e50754 100644 (file)
@@ -1,20 +1,36 @@
-error[E0277]: expected a `Fn<(proc_macro::TokenStream,)>` closure, found `unsafe extern "C" fn(i32, u32) -> u32 {foo}`
+error: proc macro functions may not be `extern "C"`
   --> $DIR/signature.rs:10:1
    |
-LL | / pub unsafe extern "C" fn foo(a: i32, b: u32) -> u32 {
-LL | |
-LL | |     loop {}
-LL | | }
-   | | ^
-   | | |
-   | |_call the function in a closure: `|| unsafe { /* code */ }`
-   |   required by a bound introduced by this call
+LL | pub unsafe extern "C" fn foo(a: i32, b: u32) -> u32 {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: proc macro functions may not be `unsafe`
+  --> $DIR/signature.rs:10:1
+   |
+LL | pub unsafe extern "C" fn foo(a: i32, b: u32) -> u32 {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: mismatched derive proc macro signature
+  --> $DIR/signature.rs:10:49
+   |
+LL | pub unsafe extern "C" fn foo(a: i32, b: u32) -> u32 {
+   |                                                 ^^^ found u32, expected type `proc_macro::TokenStream`
+   |
+   = note: derive proc macros must have a signature of `fn(TokenStream) -> TokenStream`
+
+error: mismatched derive proc macro signature
+  --> $DIR/signature.rs:10:33
+   |
+LL | pub unsafe extern "C" fn foo(a: i32, b: u32) -> u32 {
+   |                                 ^^^ found i32, expected type `proc_macro::TokenStream`
+   |
+   = note: derive proc macros must have a signature of `fn(TokenStream) -> TokenStream`
+
+error: mismatched derive proc macro signature
+  --> $DIR/signature.rs:10:38
    |
-   = help: the trait `Fn<(proc_macro::TokenStream,)>` is not implemented for fn item `unsafe extern "C" fn(i32, u32) -> u32 {foo}`
-   = note: unsafe function cannot be called generically without an unsafe block
-note: required by a bound in `ProcMacro::custom_derive`
-  --> $SRC_DIR/proc_macro/src/bridge/client.rs:LL:COL
+LL | pub unsafe extern "C" fn foo(a: i32, b: u32) -> u32 {
+   |                                      ^^^^^^ found unexpected argument
 
-error: aborting due to previous error
+error: aborting due to 5 previous errors
 
-For more information about this error, try `rustc --explain E0277`.
index 6ea238f302f3faf42db9c3df15340f7679e345c3..d76a83b02580904019ca09f8650f12311d251ed9 100644 (file)
@@ -1,6 +1,8 @@
 error[E0597]: `x` does not live long enough
   --> $DIR/do-not-suggest-adding-bound-to-opaque-type.rs:9:7
    |
+LL |     let x = ();
+   |         - binding `x` declared here
 LL |     S(&x)
    |     --^^-
    |     | |
diff --git a/tests/ui/regions/higher-ranked-implied.rs b/tests/ui/regions/higher-ranked-implied.rs
new file mode 100644 (file)
index 0000000..103884c
--- /dev/null
@@ -0,0 +1,14 @@
+// FIXME: This test should pass as the first two fields add implied bounds that
+// `'a` is equal to `'b` while the last one should simply use that fact. With
+// the current implementation this errors. We have to be careful as implied bounds
+// are only sound if they're also correctly checked.
+
+struct Inv<T>(*mut T); // `T` is invariant.
+type A = for<'a, 'b> fn(Inv<&'a &'b ()>, Inv<&'b &'a ()>, Inv<&'a ()>);
+type B = for<'a, 'b> fn(Inv<&'a &'b ()>, Inv<&'b &'a ()>, Inv<&'b ()>);
+
+fn main() {
+    let x: A = |_, _, _| ();
+    let y: B = x; //~ ERROR mismatched types
+    let _: A = y; //~ ERROR mismatched types
+}
diff --git a/tests/ui/regions/higher-ranked-implied.stderr b/tests/ui/regions/higher-ranked-implied.stderr
new file mode 100644 (file)
index 0000000..9d80eac
--- /dev/null
@@ -0,0 +1,21 @@
+error[E0308]: mismatched types
+  --> $DIR/higher-ranked-implied.rs:12:16
+   |
+LL |     let y: B = x;
+   |                ^ one type is more general than the other
+   |
+   = note: expected fn pointer `for<'a, 'b> fn(Inv<&'a &'b ()>, Inv<&'b &'a ()>, Inv<&'b ()>)`
+              found fn pointer `for<'a, 'b> fn(Inv<&'a &'b ()>, Inv<&'b &'a ()>, Inv<&'a ()>)`
+
+error[E0308]: mismatched types
+  --> $DIR/higher-ranked-implied.rs:13:16
+   |
+LL |     let _: A = y;
+   |                ^ one type is more general than the other
+   |
+   = note: expected fn pointer `for<'a, 'b> fn(Inv<&'a &'b ()>, Inv<&'b &'a ()>, Inv<&'a ()>)`
+              found fn pointer `for<'a, 'b> fn(Inv<&'a &'b ()>, Inv<&'b &'a ()>, Inv<&'b ()>)`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
index e77289287e5366f09cae79d1b25f011e89abbffb..99060a9c7f59ffe125f44fb11e322e0997b041a6 100644 (file)
@@ -1,6 +1,8 @@
 error[E0597]: `a` does not live long enough
   --> $DIR/regions-addr-of-arg.rs:5:30
    |
+LL | fn foo(a: isize) {
+   |        - binding `a` declared here
 LL |     let _p: &'static isize = &a;
    |             --------------   ^^ borrowed value does not live long enough
    |             |
index 8ef7e22536bf94a4847261ad3fe6bf476fbf88de..c83cfc1c987b6e28d0403f408cef06f744120d95 100644 (file)
@@ -18,6 +18,8 @@ error[E0597]: `y` does not live long enough
 LL | fn call1<'a>(x: &'a usize) {
    |          -- lifetime `'a` defined here
 ...
+LL |     let y: usize = 3;
+   |         - binding `y` declared here
 LL |     let z: &'a & usize = &(&y);
    |            -----------    ^^^^ borrowed value does not live long enough
    |            |
index 803d0d7449108722618bb392aca6ffa7c4d08508..c8a33bbc52236e0c58d9f78c4fba760ea5d80ad1 100644 (file)
@@ -1,6 +1,8 @@
 error[E0597]: `x` does not live long enough
   --> $DIR/regions-infer-proc-static-upvar.rs:10:13
    |
+LL |       let x = 3;
+   |           - binding `x` declared here
 LL |       let y = &x;
    |               ^^ borrowed value does not live long enough
 LL | /     foo(move|| {
index bb2740310f6a1ba8371bb1aea975334f241a4d56..ee43f9fa5724d3d2278d889dcec7fb7890a6da3f 100644 (file)
@@ -13,6 +13,8 @@ LL |         ay = z;
 error[E0597]: `y` does not live long enough
   --> $DIR/regions-nested-fns.rs:5:18
    |
+LL |     let y = 3;
+   |         - binding `y` declared here
 LL |     let mut ay = &y;
    |                  ^^ borrowed value does not live long enough
 ...
index f77d94a24b88fee2a3fc4d09f0994116b8af8d9b..18aec29ad0b74291ddfda7c480caed2725b3f592 100644 (file)
@@ -1,6 +1,8 @@
 error[E0597]: `line` does not live long enough
   --> $DIR/regions-pattern-typing-issue-19552.rs:5:14
    |
+LL |     let line = String::new();
+   |         ---- binding `line` declared here
 LL |     match [&*line] {
    |              ^^^^ borrowed value does not live long enough
 LL |         [ word ] => { assert_static(word); }
index ae60e3c0d5d671a0b973f839e7c6e1863cb1630a..0abe77a86977f4d65304e675652d290bee10de6b 100644 (file)
@@ -2,10 +2,10 @@ error[E0506]: cannot assign to `a1` because it is borrowed
   --> $DIR/regions-pattern-typing-issue-19997.rs:7:13
    |
 LL |     match (&a1,) {
-   |            --- borrow of `a1` occurs here
+   |            --- `a1` is borrowed here
 LL |         (&ref b0,) => {
 LL |             a1 = &f;
-   |             ^^^^^^^ assignment to borrowed `a1` occurs here
+   |             ^^^^^^^ `a1` is assigned to here but it was already borrowed
 LL |             drop(b0);
    |                  -- borrow later used here
 
index f78f1d822bf608849b0343cfa8189c53ea035888..310b6c224e0e77decd21ddab61faa77db891a777 100644 (file)
@@ -23,9 +23,7 @@ LL |         std::intrinsics::unlikely,
    |
    = note: expected fn item `extern "rust-intrinsic" fn(_) -> _ {likely}`
               found fn item `extern "rust-intrinsic" fn(_) -> _ {unlikely}`
-   = note: different `fn` items always have unique types, even if their signatures are the same
-   = help: change the expected type to be function pointer `extern "rust-intrinsic" fn(bool) -> bool`
-   = help: if the expected type is due to type inference, cast the expected `fn` to a function pointer: `likely as extern "rust-intrinsic" fn(bool) -> bool`
+   = note: different fn items have unique types, even if their signatures are the same
 
 error: aborting due to 3 previous errors
 
index de730ce1030f24bbab5699e3a644dc2acce470a5..ad84ebe3a504c0e99ccdc6b2963f90cca0abe78c 100644 (file)
@@ -2,7 +2,7 @@ error[E0503]: cannot use `x` because it was mutably borrowed
   --> $DIR/borrowck-non-exhaustive.rs:12:11
    |
 LL |     let y = &mut x;
-   |             ------ borrow of `x` occurs here
+   |             ------ `x` is borrowed here
 LL |     match x {
    |           ^ use of borrowed `x`
 ...
index 498a112fa9bb3f7434e6031827821cf9ba38bb69..f34ccecdd45e63bb6ded49705ced491c9c5852d4 100644 (file)
@@ -37,6 +37,11 @@ help: add a block here
    |
 LL |     if let Some(n) = opt else {
    |                         ^
+help: remove the `if` if you meant to write a `let...else` statement
+  --> $DIR/ensure-that-let-else-does-not-interact-with-let-chains.rs:24:5
+   |
+LL |     if let Some(n) = opt else {
+   |     ^^
 
 error: this `if` expression is missing a block after the condition
   --> $DIR/ensure-that-let-else-does-not-interact-with-let-chains.rs:28:5
index cf5815df56e1cddce670389423facf95ceefe986..07f6dc906c6bbf9bc56c6231b2c1371768a3c08f 100644 (file)
@@ -5,12 +5,15 @@ LL | #[target_feature(enable = "sse2")]
    | ---------------------------------- `#[target_feature]` added here
 ...
 LL |     let foo: fn() = foo;
-   |              ----   ^^^ cannot coerce functions with `#[target_feature]` to safe function pointers
-   |              |
+   |              ----   ^^^
+   |              |      |
+   |              |      cannot coerce functions with `#[target_feature]` to safe function pointers
+   |              |      help: consider casting to a fn pointer: `foo as fn()`
    |              expected due to this
    |
    = note: expected fn pointer `fn()`
                  found fn item `fn() {foo}`
+   = note: fn items are distinct from fn pointers
    = note: functions with `#[target_feature]` can only be coerced to `unsafe` function pointers
 
 error: aborting due to previous error
index cf5815df56e1cddce670389423facf95ceefe986..07f6dc906c6bbf9bc56c6231b2c1371768a3c08f 100644 (file)
@@ -5,12 +5,15 @@ LL | #[target_feature(enable = "sse2")]
    | ---------------------------------- `#[target_feature]` added here
 ...
 LL |     let foo: fn() = foo;
-   |              ----   ^^^ cannot coerce functions with `#[target_feature]` to safe function pointers
-   |              |
+   |              ----   ^^^
+   |              |      |
+   |              |      cannot coerce functions with `#[target_feature]` to safe function pointers
+   |              |      help: consider casting to a fn pointer: `foo as fn()`
    |              expected due to this
    |
    = note: expected fn pointer `fn()`
                  found fn item `fn() {foo}`
+   = note: fn items are distinct from fn pointers
    = note: functions with `#[target_feature]` can only be coerced to `unsafe` function pointers
 
 error: aborting due to previous error
index 5f93ad6e0279e969d569f7ae4ce6c7ac8815f98b..1c26eb8803d7f68088feac2dfa304537ebaa3a35 100644 (file)
@@ -1,6 +1,9 @@
 error[E0597]: `s` does not live long enough
   --> $DIR/lifetime-update.rs:20:17
    |
+LL |     let s = String::from("hello");
+   |         - binding `s` declared here
+...
 LL |         lt_str: &s,
    |                 ^^ borrowed value does not live long enough
 ...
index 65fec3becaceed9b376b13d9dbaaa4476fbb9861..91aacedfc577897b70c0bad4de441d3633bd38a4 100644 (file)
@@ -3,6 +3,7 @@
 #![feature(rustc_attrs)]
 
 use std::{
+    cell::Cell,
     ops::{Deref, CoerceUnsized, DispatchFromDyn},
     marker::Unsize,
 };
@@ -20,6 +21,20 @@ fn deref(&self) -> &T {
 impl<T: Unsize<U> + ?Sized, U: ?Sized> CoerceUnsized<Ptr<U>> for Ptr<T> {}
 impl<T: Unsize<U> + ?Sized, U: ?Sized> DispatchFromDyn<Ptr<U>> for Ptr<T> {}
 
+
+struct CellPtr<'a, T: ?Sized>(Cell<&'a T>);
+
+impl<'a, T: ?Sized> Deref for CellPtr<'a, T> {
+    type Target = T;
+
+    fn deref(&self) -> &T {
+        self.0.get()
+    }
+}
+
+impl<'a, T: Unsize<U> + ?Sized, U: ?Sized> CoerceUnsized<CellPtr<'a, U>> for CellPtr<'a, T> {}
+impl<'a, T: Unsize<U> + ?Sized, U: ?Sized> DispatchFromDyn<CellPtr<'a, U>> for CellPtr<'a, T> {}
+
 struct Wrapper<T: ?Sized>(T);
 
 impl<T: ?Sized> Deref for Wrapper<T> {
@@ -42,6 +57,7 @@ trait Trait {
     fn ptr_wrapper(self: Ptr<Wrapper<Self>>) -> i32;
     fn wrapper_ptr(self: Wrapper<Ptr<Self>>) -> i32;
     fn wrapper_ptr_wrapper(self: Wrapper<Ptr<Wrapper<Self>>>) -> i32;
+    fn cell(self: CellPtr<Self>) -> i32;
 }
 
 impl Trait for i32 {
@@ -54,6 +70,9 @@ fn wrapper_ptr(self: Wrapper<Ptr<Self>>) -> i32 {
     fn wrapper_ptr_wrapper(self: Wrapper<Ptr<Wrapper<Self>>>) -> i32 {
         ***self
     }
+    fn cell(self: CellPtr<Self>) -> i32 {
+        *self
+    }
 }
 
 fn main() {
@@ -65,4 +84,7 @@ fn main() {
 
     let wpw = Wrapper(Ptr(Box::new(Wrapper(7)))) as Wrapper<Ptr<Wrapper<dyn Trait>>>;
     assert_eq!(wpw.wrapper_ptr_wrapper(), 7);
+
+    let c = CellPtr(Cell::new(&8)) as CellPtr<dyn Trait>;
+    assert_eq!(c.cell(), 8);
 }
index 0b8e134c9662e8f8ef7c1a7c2db749ed0e3cc45d..6faa4477d8c5d3476aa432a512984d448c6104bc 100644 (file)
@@ -1,6 +1,8 @@
 error[E0597]: `x` does not live long enough
   --> $DIR/issue-61882-2.rs:6:14
    |
+LL |         let x = 0;
+   |             - binding `x` declared here
 LL |         Self(&x);
    |              ^^
    |              |
index 48b42bc78253f59842a5fe00a4416b3bea2e24b4..9711dad80785b6cbeec10aa0bb6a3cf69ced645f 100644 (file)
@@ -47,6 +47,9 @@ LL |         foo(f);
 error[E0505]: cannot move out of `f` because it is borrowed
   --> $DIR/borrowck-call-is-borrow-issue-12224.rs:55:16
    |
+LL |     let mut f = move |g: Box<dyn FnMut(isize)>, b: isize| {
+   |         ----- binding `f` declared here
+...
 LL |     f(Box::new(|a| {
    |     -          ^^^ move out of `f` occurs here
    |     |
index 18abfb5c3fbecb2c589e7bde35cc77e7b7008895..ad556f281df126b5b48419044847fbd44d2ef781 100644 (file)
@@ -8,6 +8,7 @@ fn f() {
 
     {
         let young = ['y'];       // statement 3
+        //~^ NOTE binding `young` declared here
 
         v2.push(&young[0]);      // statement 4
         //~^ ERROR `young[_]` does not live long enough
index 2dc29a78d204d15a35b4e55818b8e29f76c8e6d3..545b235a552d18986f6810756dc92d5c330860bb 100644 (file)
@@ -1,6 +1,9 @@
 error[E0597]: `young[_]` does not live long enough
-  --> $DIR/borrowck-let-suggestion-suffixes.rs:12:17
+  --> $DIR/borrowck-let-suggestion-suffixes.rs:13:17
    |
+LL |         let young = ['y'];       // statement 3
+   |             ----- binding `young` declared here
+...
 LL |         v2.push(&young[0]);      // statement 4
    |                 ^^^^^^^^^ borrowed value does not live long enough
 ...
@@ -11,7 +14,7 @@ LL |     (v1, v2, v3, /* v4 is above. */ v5).use_ref();
    |          -- borrow later used here
 
 error[E0716]: temporary value dropped while borrowed
-  --> $DIR/borrowck-let-suggestion-suffixes.rs:19:14
+  --> $DIR/borrowck-let-suggestion-suffixes.rs:20:14
    |
 LL |     v3.push(&id('x'));           // statement 6
    |              ^^^^^^^ - temporary value is freed at the end of this statement
@@ -28,7 +31,7 @@ LL ~     v3.push(&binding);           // statement 6
    |
 
 error[E0716]: temporary value dropped while borrowed
-  --> $DIR/borrowck-let-suggestion-suffixes.rs:29:18
+  --> $DIR/borrowck-let-suggestion-suffixes.rs:30:18
    |
 LL |         v4.push(&id('y'));
    |                  ^^^^^^^ - temporary value is freed at the end of this statement
@@ -41,7 +44,7 @@ LL |         v4.use_ref();
    = note: consider using a `let` binding to create a longer lived value
 
 error[E0716]: temporary value dropped while borrowed
-  --> $DIR/borrowck-let-suggestion-suffixes.rs:40:14
+  --> $DIR/borrowck-let-suggestion-suffixes.rs:41:14
    |
 LL |     v5.push(&id('z'));
    |              ^^^^^^^ - temporary value is freed at the end of this statement
index 53c9404620f35d8633354a9eb9a113352852fe9d..281248626c82609a881e1caff5b1ce56b9bb3de5 100644 (file)
@@ -1,6 +1,8 @@
 error[E0597]: `*a` does not live long enough
   --> $DIR/destructor-restrictions.rs:8:10
    |
+LL |         let a = Box::new(RefCell::new(4));
+   |             - binding `a` declared here
 LL |         *a.borrow() + 1
    |          ^^^^^^^^^^
    |          |
index 229d17e1cf903c65f5477da8e63c96758e958c04..097fb6219f1fde0924c304df52c75360e3b92699 100644 (file)
@@ -1,6 +1,8 @@
 error[E0597]: `*m` does not live long enough
   --> $DIR/dropck-object-cycle.rs:27:31
    |
+LL |     let m : Box<dyn Trait+'static> = make_val();
+   |         - binding `m` declared here
 LL |     assert_eq!(object_invoke1(&*m), (4,5));
    |                               ^^^ borrowed value does not live long enough
 ...
index 068c779ae52673be950d27f84d13255bea70f6b5..23ebc8d598c672d1d05b13227e5e7587e3a24c27 100644 (file)
@@ -1,6 +1,9 @@
 error[E0597]: `b2` does not live long enough
   --> $DIR/dropck_arr_cycle_checked.rs:93:24
    |
+LL |     let (b1, b2, b3);
+   |              -- binding `b2` declared here
+...
 LL |     b1.a[0].v.set(Some(&b2));
    |                        ^^^ borrowed value does not live long enough
 ...
@@ -15,6 +18,9 @@ LL | }
 error[E0597]: `b3` does not live long enough
   --> $DIR/dropck_arr_cycle_checked.rs:95:24
    |
+LL |     let (b1, b2, b3);
+   |                  -- binding `b3` declared here
+...
 LL |     b1.a[1].v.set(Some(&b3));
    |                        ^^^ borrowed value does not live long enough
 ...
@@ -29,6 +35,9 @@ LL | }
 error[E0597]: `b1` does not live long enough
   --> $DIR/dropck_arr_cycle_checked.rs:99:24
    |
+LL |     let (b1, b2, b3);
+   |          -- binding `b1` declared here
+...
 LL |     b3.a[0].v.set(Some(&b1));
    |                        ^^^ borrowed value does not live long enough
 ...
index 07ae138ac71eae3c91807e2acc1c56a719389299..1e75e3b2fa12180792a912a7df9ae755234cd161 100644 (file)
@@ -1,6 +1,8 @@
 error[E0597]: `d2` does not live long enough
   --> $DIR/dropck_direct_cycle_with_drop.rs:36:19
    |
+LL |     let (d1, d2) = (D::new(format!("d1")), D::new(format!("d2")));
+   |              -- binding `d2` declared here
 LL |     d1.p.set(Some(&d2));
    |                   ^^^ borrowed value does not live long enough
 ...
@@ -15,6 +17,9 @@ LL | }
 error[E0597]: `d1` does not live long enough
   --> $DIR/dropck_direct_cycle_with_drop.rs:38:19
    |
+LL |     let (d1, d2) = (D::new(format!("d1")), D::new(format!("d2")));
+   |          -- binding `d1` declared here
+...
 LL |     d2.p.set(Some(&d1));
    |                   ^^^ borrowed value does not live long enough
 LL |
index 76e90574cef440de02cc5ec826ec24c7072637f8..24a2c9089f5b1f1a9265fe8a27b189097c9ecfeb 100644 (file)
@@ -1,6 +1,9 @@
 error[E0597]: `bomb` does not live long enough
   --> $DIR/dropck_misc_variants.rs:23:36
    |
+LL |     let (_w, bomb);
+   |              ---- binding `bomb` declared here
+LL |     bomb = vec![""];
 LL |     _w = Wrap::<&[&str]>(NoisyDrop(&bomb));
    |                                    ^^^^^ borrowed value does not live long enough
 LL | }
@@ -14,6 +17,9 @@ LL | }
 error[E0597]: `v` does not live long enough
   --> $DIR/dropck_misc_variants.rs:31:27
    |
+LL |     let (_w,v);
+   |             - binding `v` declared here
+...
 LL |         let u = NoisyDrop(&v);
    |                           ^^ borrowed value does not live long enough
 ...
index 7ff991c0c3737d38de82cc72f9bc516e5a15d984..5817439c0d8555aff362c515e90b9613f4acc167 100644 (file)
@@ -1,6 +1,9 @@
 error[E0597]: `c2` does not live long enough
   --> $DIR/dropck_vec_cycle_checked.rs:98:24
    |
+LL |     let (mut c1, mut c2, mut c3);
+   |                  ------ binding `c2` declared here
+...
 LL |     c1.v[0].v.set(Some(&c2));
    |                        ^^^ borrowed value does not live long enough
 ...
@@ -15,6 +18,9 @@ LL | }
 error[E0597]: `c3` does not live long enough
   --> $DIR/dropck_vec_cycle_checked.rs:100:24
    |
+LL |     let (mut c1, mut c2, mut c3);
+   |                          ------ binding `c3` declared here
+...
 LL |     c1.v[1].v.set(Some(&c3));
    |                        ^^^ borrowed value does not live long enough
 ...
@@ -29,6 +35,9 @@ LL | }
 error[E0597]: `c1` does not live long enough
   --> $DIR/dropck_vec_cycle_checked.rs:104:24
    |
+LL |     let (mut c1, mut c2, mut c3);
+   |          ------ binding `c1` declared here
+...
 LL |     c3.v[0].v.set(Some(&c1));
    |                        ^^^ borrowed value does not live long enough
 ...
index 3c2022748f0944339f99e3560083a49cd3cf1f7c..e1a377203e2962551a4d7425ac5cb630201961e7 100644 (file)
@@ -1,6 +1,8 @@
 error[E0597]: `y` does not live long enough
   --> $DIR/issue-23338-locals-die-before-temps-of-body.rs:10:5
    |
+LL |     let y = x;
+   |         - binding `y` declared here
 LL |     y.borrow().clone()
    |     ^^^^^^^^^^
    |     |
@@ -22,6 +24,8 @@ LL |     let x = y.borrow().clone(); x
 error[E0597]: `y` does not live long enough
   --> $DIR/issue-23338-locals-die-before-temps-of-body.rs:17:9
    |
+LL |         let y = x;
+   |             - binding `y` declared here
 LL |         y.borrow().clone()
    |         ^^^^^^^^^^
    |         |
index 809e60a8c8aac99c664c47b5f7ad0dddad87bf0c..c3b6d7580b4e020598e555b9fbe2f8de8d1da023 100644 (file)
@@ -1,6 +1,9 @@
 error[E0597]: `d1` does not live long enough
   --> $DIR/issue-24805-dropck-child-has-items-via-parent.rs:28:18
    |
+LL |     let (_d, d1);
+   |              -- binding `d1` declared here
+...
 LL |     _d = D_Child(&d1);
    |                  ^^^ borrowed value does not live long enough
 ...
index 2e217066915d3cacad84e350ae8eff5bc198ff26..e52c57d9ab1f824ac0337cd8d614078776e0dc38 100644 (file)
@@ -1,6 +1,9 @@
 error[E0597]: `d1` does not live long enough
   --> $DIR/issue-24805-dropck-trait-has-items.rs:37:26
    |
+LL |     let (_d, d1);
+   |              -- binding `d1` declared here
+LL |     d1 = D_HasSelfMethod(1);
 LL |     _d = D_HasSelfMethod(&d1);
    |                          ^^^ borrowed value does not live long enough
 LL | }
@@ -14,6 +17,9 @@ LL | }
 error[E0597]: `d1` does not live long enough
   --> $DIR/issue-24805-dropck-trait-has-items.rs:43:33
    |
+LL |     let (_d, d1);
+   |              -- binding `d1` declared here
+LL |     d1 = D_HasMethodWithSelfArg(1);
 LL |     _d = D_HasMethodWithSelfArg(&d1);
    |                                 ^^^ borrowed value does not live long enough
 LL | }
@@ -27,6 +33,9 @@ LL | }
 error[E0597]: `d1` does not live long enough
   --> $DIR/issue-24805-dropck-trait-has-items.rs:49:20
    |
+LL |     let (_d, d1);
+   |              -- binding `d1` declared here
+LL |     d1 = D_HasType(1);
 LL |     _d = D_HasType(&d1);
    |                    ^^^ borrowed value does not live long enough
 LL | }
index 18a3dc9e6defa3855ab01aa200b45accadfd7184..83db4d509d49988b33fe3fe59d20dc7b9de4b231 100644 (file)
@@ -1,6 +1,9 @@
 error[E0597]: `d1` does not live long enough
   --> $DIR/issue-24895-copy-clone-dropck.rs:27:14
    |
+LL |     let (d2, d1);
+   |              -- binding `d1` declared here
+LL |     d1 = D(34, "d1");
 LL |     d2 = D(S(&d1, "inner"), "d2");
    |              ^^^ borrowed value does not live long enough
 LL | }
index d70a4afc1bf340e6c5fa88cfc8387e302895582b..1e0276f0c3694b6376e97817a4c4ceb9dfb57e1b 100644 (file)
@@ -1,6 +1,8 @@
 error[E0597]: `container` does not live long enough
   --> $DIR/issue-25199.rs:70:27
    |
+LL |     let container = Container::new();
+   |         --------- binding `container` declared here
 LL |     let test = Test{test: &container};
    |                           ^^^^^^^^^^ borrowed value does not live long enough
 ...
index 1e939c484fb7b35291775a78020242aded9791b6..fea6e001238b59294353970fc4bcc88da054e0f2 100644 (file)
@@ -1,6 +1,9 @@
 error[E0597]: `ticking` does not live long enough
   --> $DIR/issue-26656.rs:40:35
    |
+LL |     let (mut zook, ticking);
+   |                    ------- binding `ticking` declared here
+...
 LL |     zook.button = B::BigRedButton(&ticking);
    |                                   ^^^^^^^^ borrowed value does not live long enough
 LL | }
index 71fbd60ee733b27e0d4a2fedc54293d5f72e10aa..28ee7acd90e8c5b3ca80c5044c15f784aabfe55b 100644 (file)
@@ -1,6 +1,9 @@
 error[E0597]: `x` does not live long enough
   --> $DIR/issue-29106.rs:16:26
    |
+LL |         let (y, x);
+   |                 - binding `x` declared here
+LL |         x = "alive".to_string();
 LL |         y = Arc::new(Foo(&x));
    |                          ^^ borrowed value does not live long enough
 LL |     }
@@ -14,6 +17,9 @@ LL |     }
 error[E0597]: `x` does not live long enough
   --> $DIR/issue-29106.rs:23:25
    |
+LL |         let (y, x);
+   |                 - binding `x` declared here
+LL |         x = "alive".to_string();
 LL |         y = Rc::new(Foo(&x));
    |                         ^^ borrowed value does not live long enough
 LL |     }
index 79a0ebaeb8db6c8b6ab999999737bd3194d2280e..6c330c1a094758b9de3345dbd87c6a294f1dca9b 100644 (file)
@@ -1,6 +1,8 @@
 error[E0597]: `a` does not live long enough
   --> $DIR/issue-36537.rs:5:13
    |
+LL |         let a = 42;
+   |             - binding `a` declared here
 LL |         p = &a;
    |             ^^ borrowed value does not live long enough
 ...
index 57f80214a4f83ad2c9988fda6677fdf434aaea07..a0afd33f7c7c4c941616bf1b772a47fe775f53b4 100644 (file)
@@ -2,11 +2,10 @@ error[E0597]: `foo` does not live long enough
   --> $DIR/issue-40157.rs:2:53
    |
 LL |     {println!("{:?}", match { let foo = vec![1, 2]; foo.get(1) } { x => x });}
-   |                             ------------------------^^^^^^^^^^--
-   |                             |                       |          |
-   |                             |                       |          `foo` dropped here while still borrowed
-   |                             |                       borrowed value does not live long enough
-   |                             borrow later used here
+   |                                   ---               ^^^^^^^^^^ - `foo` dropped here while still borrowed
+   |                                   |                 |
+   |                                   |                 borrowed value does not live long enough
+   |                                   binding `foo` declared here
 
 error: aborting due to previous error
 
index 3119ddd03cc26654a20e1d31d9ce559e26aeb7f3..94c450c7b1ececc99ca46eff2b6086bb4ae0d143 100644 (file)
@@ -1,6 +1,9 @@
 error[E0597]: `first_dropped` does not live long enough
   --> $DIR/issue28498-reject-lifetime-param.rs:32:19
    |
+LL |     let (foo1, first_dropped);
+   |                ------------- binding `first_dropped` declared here
+...
 LL |     foo1 = Foo(1, &first_dropped);
    |                   ^^^^^^^^^^^^^^ borrowed value does not live long enough
 ...
index 60e8a648cd5979d37f780f315fd13fb6b199cb90..e133f75d57bb7628e3c7d01090bc497849002105 100644 (file)
@@ -1,6 +1,9 @@
 error[E0597]: `first_dropped` does not live long enough
   --> $DIR/issue28498-reject-passed-to-fn.rs:34:19
    |
+LL |     let (foo1, first_dropped);
+   |                ------------- binding `first_dropped` declared here
+...
 LL |     foo1 = Foo(1, &first_dropped, Box::new(callback));
    |                   ^^^^^^^^^^^^^^ borrowed value does not live long enough
 ...
index 22e4a8205b617723a856dd8f7e904ce7c962c368..9ab3cdd1343a1700dbf007fc2d1cf3fde58c5c4d 100644 (file)
@@ -1,6 +1,9 @@
 error[E0597]: `first_dropped` does not live long enough
   --> $DIR/issue28498-reject-trait-bound.rs:34:19
    |
+LL |     let (foo1, first_dropped);
+   |                ------------- binding `first_dropped` declared here
+...
 LL |     foo1 = Foo(1, &first_dropped);
    |                   ^^^^^^^^^^^^^^ borrowed value does not live long enough
 ...
index 4d976a7bbfa47bb52b59dd675606d3a49273a86b..be56f9489c770391aa139eab90b13fb72f522fe6 100644 (file)
@@ -1,6 +1,8 @@
 error[E0597]: `b` does not live long enough
   --> $DIR/mut-ptr-cant-outlive-ref.rs:8:15
    |
+LL |         let b = m.borrow();
+   |             - binding `b` declared here
 LL |         p = &*b;
    |               ^ borrowed value does not live long enough
 LL |     }
index 8ca8156b0830cbaaa8fe83c0dd97b4ed582f9dd7..d7084b00ba4027a78516321624e1d71bc2248b59 100644 (file)
@@ -3,7 +3,9 @@ error[E0597]: `a` does not live long enough
    |
 LL |     let r = {
    |         - borrow later stored here
-...
+LL |         let a = 42;
+   |             - binding `a` declared here
+LL |         let b = 42;
 LL |         &a..&b
    |         ^^ borrowed value does not live long enough
 LL |     };
@@ -14,7 +16,9 @@ error[E0597]: `b` does not live long enough
    |
 LL |     let r = {
    |         - borrow later stored here
-...
+LL |         let a = 42;
+LL |         let b = 42;
+   |             - binding `b` declared here
 LL |         &a..&b
    |             ^^ borrowed value does not live long enough
 LL |     };
index 0b985de609c26debdb98dbdcca279a3a685f655f..fb3fad6ae9050f4873d8293533ad35cbc18ed6be 100644 (file)
@@ -1,6 +1,8 @@
 error[E0597]: `c` does not live long enough
   --> $DIR/regionck-unboxed-closure-lifetimes.rs:8:21
    |
+LL |         let c = 1;
+   |             - binding `c` declared here
 LL |         let c_ref = &c;
    |                     ^^ borrowed value does not live long enough
 ...
index 2e584d9a884f174f5f743cb2828c3c06a4e3a8fd..fed40a4fdd2a5984674f2d8ac889bf26cf439fe6 100644 (file)
@@ -1,6 +1,8 @@
 error[E0597]: `tmp0` does not live long enough
   --> $DIR/regions-close-over-type-parameter-2.rs:23:20
    |
+LL |         let tmp0 = 3;
+   |             ---- binding `tmp0` declared here
 LL |         let tmp1 = &tmp0;
    |                    ^^^^^ borrowed value does not live long enough
 LL |         repeater3(tmp1)
index 42df668529749df6d739a23fd8c37827cc5fde92..e5c7d8b26ab00e31fc8c39b88d583e8c4a0b2b68 100644 (file)
@@ -2,7 +2,9 @@ error[E0597]: `x` does not live long enough
   --> $DIR/regions-escape-loop-via-variable.rs:11:13
    |
 LL |         let x = 1 + *p;
-   |                     -- borrow later used here
+   |             -       -- borrow later used here
+   |             |
+   |             binding `x` declared here
 LL |         p = &x;
    |             ^^ borrowed value does not live long enough
 LL |     }
index 2b649307739f5c89b08ced82852cc6a4b03ce652..532ac3606c544e9fada531cd4277efb517207a92 100644 (file)
@@ -2,7 +2,7 @@ error[E0503]: cannot use `x` because it was mutably borrowed
   --> $DIR/regions-escape-loop-via-vec.rs:5:11
    |
 LL |     let mut _y = vec![&mut x];
-   |                       ------ borrow of `x` occurs here
+   |                       ------ `x` is borrowed here
 LL |     while x < 10 {
    |           ^ use of borrowed `x`
 LL |         let mut z = x;
@@ -13,7 +13,7 @@ error[E0503]: cannot use `x` because it was mutably borrowed
   --> $DIR/regions-escape-loop-via-vec.rs:6:21
    |
 LL |     let mut _y = vec![&mut x];
-   |                       ------ borrow of `x` occurs here
+   |                       ------ `x` is borrowed here
 LL |     while x < 10 {
 LL |         let mut z = x;
    |                     ^ use of borrowed `x`
@@ -23,11 +23,10 @@ LL |         _y.push(&mut z);
 error[E0597]: `z` does not live long enough
   --> $DIR/regions-escape-loop-via-vec.rs:7:17
    |
+LL |         let mut z = x;
+   |             ----- binding `z` declared here
 LL |         _y.push(&mut z);
-   |         --------^^^^^^-
-   |         |       |
-   |         |       borrowed value does not live long enough
-   |         borrow later used here
+   |                 ^^^^^^ borrowed value does not live long enough
 ...
 LL |     }
    |     - `z` dropped here while still borrowed
@@ -36,7 +35,7 @@ error[E0503]: cannot use `x` because it was mutably borrowed
   --> $DIR/regions-escape-loop-via-vec.rs:9:9
    |
 LL |     let mut _y = vec![&mut x];
-   |                       ------ borrow of `x` occurs here
+   |                       ------ `x` is borrowed here
 ...
 LL |         _y.push(&mut z);
    |         --------------- borrow later used here
index fd67c65c4e9170d3bebb44b4d43831d6deddb620..47931db84cabe0086a8ad4cade5d4bb402e49b41 100644 (file)
@@ -1,6 +1,9 @@
 error[E0597]: `*x` does not live long enough
   --> $DIR/regions-infer-borrow-scope-within-loop.rs:13:20
    |
+LL |         let x = make_box();
+   |             - binding `x` declared here
+...
 LL |         y = borrow(&*x);
    |                    ^^^ borrowed value does not live long enough
 ...
index 65d10c1305b8c8480a4899e5667afc1b783f9ef7..bae0befcacaa7876877b6c77d1dbc7d3bc9a766c 100644 (file)
@@ -4,6 +4,7 @@ error[E0597]: `x` does not live long enough
 LL |     let bad = {
    |         --- borrow later stored here
 LL |         let x = 1;
+   |             - binding `x` declared here
 LL |         let y = &x;
    |                 ^^ borrowed value does not live long enough
 ...
index bcd07e116477769fa44e720d4a0237f53908877c..b0267fa6f43b073ff832b88df3c52e889bf9abcb 100644 (file)
@@ -4,6 +4,7 @@ error[E0597]: `x` does not live long enough
 LL |     let lock = {
    |         ---- borrow later stored here
 LL |         let x = 1;
+   |             - binding `x` declared here
 LL |         Mutex::new(&x)
    |                    ^^ borrowed value does not live long enough
 LL |     };
@@ -15,6 +16,7 @@ error[E0597]: `x` does not live long enough
 LL |     let lock = {
    |         ---- borrow later stored here
 LL |         let x = 1;
+   |             - binding `x` declared here
 LL |         RwLock::new(&x)
    |                     ^^ borrowed value does not live long enough
 LL |     };
@@ -25,7 +27,9 @@ error[E0597]: `x` does not live long enough
    |
 LL |     let (_tx, rx) = {
    |          --- borrow later used here
-...
+LL |         let x = 1;
+   |             - binding `x` declared here
+LL |         let (tx, rx) = mpsc::channel();
 LL |         let _ = tx.send(&x);
    |                         ^^ borrowed value does not live long enough
 LL |         (tx, rx)
index 5d493a3e4ee5555cfb2dd559196e8e1b11e1c5ca..7dfe94bca603f553b1ac9437f80ed48bad8fcf6f 100644 (file)
@@ -1,6 +1,9 @@
 error[E0505]: cannot move out of `y` because it is borrowed
   --> $DIR/send-is-not-static-std-sync.rs:13:10
    |
+LL |     let y = Box::new(1);
+   |         - binding `y` declared here
+LL |     let lock = Mutex::new(&x);
 LL |     *lock.lock().unwrap() = &*y;
    |                             --- borrow of `*y` occurs here
 LL |     drop(y);
@@ -12,6 +15,8 @@ LL |         *lock.lock().unwrap() = &z;
 error[E0597]: `z` does not live long enough
   --> $DIR/send-is-not-static-std-sync.rs:16:33
    |
+LL |         let z = 2;
+   |             - binding `z` declared here
 LL |         *lock.lock().unwrap() = &z;
    |                                 ^^ borrowed value does not live long enough
 LL |     }
@@ -23,6 +28,9 @@ LL |     lock.use_ref(); // (Mutex is #[may_dangle] so its dtor does not use `z`
 error[E0505]: cannot move out of `y` because it is borrowed
   --> $DIR/send-is-not-static-std-sync.rs:27:10
    |
+LL |     let y = Box::new(1);
+   |         - binding `y` declared here
+LL |     let lock = RwLock::new(&x);
 LL |     *lock.write().unwrap() = &*y;
    |                              --- borrow of `*y` occurs here
 LL |     drop(y);
@@ -34,6 +42,8 @@ LL |         *lock.write().unwrap() = &z;
 error[E0597]: `z` does not live long enough
   --> $DIR/send-is-not-static-std-sync.rs:30:34
    |
+LL |         let z = 2;
+   |             - binding `z` declared here
 LL |         *lock.write().unwrap() = &z;
    |                                  ^^ borrowed value does not live long enough
 LL |     }
@@ -45,6 +55,9 @@ LL |     lock.use_ref(); // (RwLock is #[may_dangle] so its dtor does not use `z
 error[E0505]: cannot move out of `y` because it is borrowed
   --> $DIR/send-is-not-static-std-sync.rs:43:10
    |
+LL |     let y = Box::new(1);
+   |         - binding `y` declared here
+...
 LL |     tx.send(&*y);
    |             --- borrow of `*y` occurs here
 LL |     drop(y);
@@ -56,6 +69,8 @@ LL |         tx.send(&z).unwrap();
 error[E0597]: `z` does not live long enough
   --> $DIR/send-is-not-static-std-sync.rs:46:17
    |
+LL |         let z = 2;
+   |             - binding `z` declared here
 LL |         tx.send(&z).unwrap();
    |                 ^^ borrowed value does not live long enough
 LL |     }
index f87c32d1ad0c6dd542eae38e86879ee1ceea5b0a..f2fefca414ec42813e2868baf2f08eb2df9a43dd 100644 (file)
@@ -1,6 +1,9 @@
 error[E0597]: `c2` does not live long enough
   --> $DIR/vec-must-not-hide-type-from-dropck.rs:117:24
    |
+LL |     let (mut c1, mut c2);
+   |                  ------ binding `c2` declared here
+...
 LL |     c1.v[0].v.set(Some(&c2));
    |                        ^^^ borrowed value does not live long enough
 ...
@@ -15,6 +18,9 @@ LL | }
 error[E0597]: `c1` does not live long enough
   --> $DIR/vec-must-not-hide-type-from-dropck.rs:119:24
    |
+LL |     let (mut c1, mut c2);
+   |          ------ binding `c1` declared here
+...
 LL |     c2.v[0].v.set(Some(&c1));
    |                        ^^^ borrowed value does not live long enough
 LL |
index 684e7845313252be913bab7143748de1f38ab1a5..73f27144af423fcf6b66e7889d49fd7954913195 100644 (file)
@@ -1,6 +1,9 @@
 error[E0597]: `x` does not live long enough
   --> $DIR/vec_refs_data_with_early_death.rs:17:12
    |
+LL |     let x: i8 = 3;
+   |         - binding `x` declared here
+...
 LL |     v.push(&x);
    |            ^^ borrowed value does not live long enough
 ...
@@ -15,6 +18,9 @@ LL | }
 error[E0597]: `y` does not live long enough
   --> $DIR/vec_refs_data_with_early_death.rs:19:12
    |
+LL |     let y: i8 = 4;
+   |         - binding `y` declared here
+...
 LL |     v.push(&y);
    |            ^^ borrowed value does not live long enough
 ...
index 6b0b008208f17145097e6eb6197b6ef54a679247..64c2d0f1606652c4c9ca3b519b72e557e4aeac03 100644 (file)
@@ -4,6 +4,7 @@ error[E0597]: `pointer` does not live long enough
 LL |     let dangling = {
    |         -------- borrow later stored here
 LL |         let pointer = Box::new(42);
+   |             ------- binding `pointer` declared here
 LL |         f2.xmute(&pointer)
    |                  ^^^^^^^^ borrowed value does not live long enough
 LL |     };
index ef07a89315f4088ddd653b649a5e0d8cf1f99fd3..e22411b13b776b968140a6716005dc1c2384d11e 100644 (file)
@@ -9,6 +9,8 @@ LL | fn f<'a: 'static>(_: &'a i32) {}
 error[E0597]: `x` does not live long enough
   --> $DIR/static-lifetime-bound.rs:5:7
    |
+LL |     let x = 0;
+   |         - binding `x` declared here
 LL |     f(&x);
    |     --^^-
    |     | |
index 67b478bdb75c35a38f662e1609457ae083522fb7..f68939d0ec8c91b56858f119aa88816cf9640af2 100644 (file)
@@ -2,10 +2,14 @@ error[E0308]: mismatched types
   --> $DIR/static-reference-to-fn-1.rs:17:15
    |
 LL |         func: &foo,
-   |               ^^^^ expected fn pointer, found fn item
+   |               ^^^^
+   |               |
+   |               expected fn pointer, found fn item
+   |               help: consider casting to a fn pointer: `&(foo as fn() -> Option<isize>)`
    |
    = note: expected reference `&fn() -> Option<isize>`
               found reference `&fn() -> Option<isize> {foo}`
+   = note: fn items are distinct from fn pointers
 
 error: aborting due to previous error
 
index 1ee358ba8368e8603e15d4d6f6905888fa20dc80..4e34e10e377896da15c8db53717aaa6e6b91f7c7 100644 (file)
@@ -5,6 +5,7 @@ LL |     test::<Cell<i32>>();
    |            ^^^^^^^^^ `Cell<i32>` cannot be shared between threads safely
    |
    = help: the trait `Sync` is not implemented for `Cell<i32>`
+   = note: if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` or `std::sync::atomic::AtomicI32` instead
 note: required by a bound in `test`
   --> $DIR/not-sync.rs:5:12
    |
@@ -18,6 +19,7 @@ LL |     test::<RefCell<i32>>();
    |            ^^^^^^^^^^^^ `RefCell<i32>` cannot be shared between threads safely
    |
    = help: the trait `Sync` is not implemented for `RefCell<i32>`
+   = note: if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` instead
 note: required by a bound in `test`
   --> $DIR/not-sync.rs:5:12
    |
diff --git a/tests/ui/suggestions/assoc-const-without-self.rs b/tests/ui/suggestions/assoc-const-without-self.rs
new file mode 100644 (file)
index 0000000..95070ec
--- /dev/null
@@ -0,0 +1,11 @@
+struct Foo;
+
+impl Foo {
+    const A_CONST: usize = 1;
+
+    fn foo() -> usize {
+        A_CONST //~ ERROR cannot find value `A_CONST` in this scope
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/suggestions/assoc-const-without-self.stderr b/tests/ui/suggestions/assoc-const-without-self.stderr
new file mode 100644 (file)
index 0000000..88d72da
--- /dev/null
@@ -0,0 +1,14 @@
+error[E0425]: cannot find value `A_CONST` in this scope
+  --> $DIR/assoc-const-without-self.rs:7:9
+   |
+LL |         A_CONST
+   |         ^^^^^^^ not found in this scope
+   |
+help: consider using the associated constant
+   |
+LL |         Self::A_CONST
+   |         ++++++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0425`.
index cbdb94877bdb7fbf897d0020c928bc6d718646a8..0f179438a1263bacb0dbed76f3d8df47ec93981d 100644 (file)
@@ -1,6 +1,8 @@
 error[E0505]: cannot move out of `a` because it is borrowed
   --> $DIR/borrow-for-loop-head.rs:4:18
    |
+LL |     let a = vec![1, 2, 3];
+   |         - binding `a` declared here
 LL |     for i in &a {
    |              -- borrow of `a` occurs here
 LL |         for j in a {
index 1d3dff3be3476d4b0678d0881b06c855fc7ca905..94acda73c4efe2bc4aacb938093afe7aa1c6c23f 100644 (file)
@@ -7,7 +7,7 @@ LL |     func(|| {
    |          -- captured by this `FnMut` closure
 LL |         // Shouldn't suggest `move ||.as_ref()` here
 LL |         move || {
-   |         ^^^^^^^ move out of `var` occurs here
+   |         ^^^^^^^ `var` is moved here
 LL |
 LL |             var = Some(NotCopyable);
    |             ---
index 10447ba7089caae7eff7065aefdd1ccf4b8a63f3..7b194259349b8c090f5d82d463fde2ad62897b80 100644 (file)
@@ -19,8 +19,8 @@ error: cannot move out of value because it is borrowed
 LL |     let ref _moved @ _from = String::from("foo");
    |         ----------^^^-----
    |         |            |
-   |         |            value moved into `_from` here
-   |         value borrowed, by `_moved`, here
+   |         |            value is moved into `_from` here
+   |         value is borrowed by `_moved` here
 
 error: cannot move out of value because it is borrowed
   --> $DIR/ref-pattern-binding.rs:15:9
@@ -28,8 +28,8 @@ error: cannot move out of value because it is borrowed
 LL |     let ref _moved @ S { f } = S { f: String::from("foo") };
    |         ----------^^^^^^^-^^
    |         |                |
-   |         |                value moved into `f` here
-   |         value borrowed, by `_moved`, here
+   |         |                value is moved into `f` here
+   |         value is borrowed by `_moved` here
 
 error: borrow of moved value
   --> $DIR/ref-pattern-binding.rs:18:9
diff --git a/tests/ui/sync/mutexguard-sync.rs b/tests/ui/sync/mutexguard-sync.rs
new file mode 100644 (file)
index 0000000..b564183
--- /dev/null
@@ -0,0 +1,13 @@
+// MutexGuard<Cell<i32>> must not be Sync, that would be unsound.
+use std::sync::Mutex;
+use std::cell::Cell;
+
+fn test_sync<T: Sync>(_t: T) {}
+
+fn main()
+{
+    let m = Mutex::new(Cell::new(0i32));
+    let guard = m.lock().unwrap();
+    test_sync(guard);
+    //~^ ERROR `Cell<i32>` cannot be shared between threads safely [E0277]
+}
diff --git a/tests/ui/sync/mutexguard-sync.stderr b/tests/ui/sync/mutexguard-sync.stderr
new file mode 100644 (file)
index 0000000..4dc5571
--- /dev/null
@@ -0,0 +1,20 @@
+error[E0277]: `Cell<i32>` cannot be shared between threads safely
+  --> $DIR/mutexguard-sync.rs:11:15
+   |
+LL |     test_sync(guard);
+   |     --------- ^^^^^ `Cell<i32>` cannot be shared between threads safely
+   |     |
+   |     required by a bound introduced by this call
+   |
+   = help: the trait `Sync` is not implemented for `Cell<i32>`
+   = note: if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` or `std::sync::atomic::AtomicI32` instead
+   = note: required for `MutexGuard<'_, Cell<i32>>` to implement `Sync`
+note: required by a bound in `test_sync`
+  --> $DIR/mutexguard-sync.rs:5:17
+   |
+LL | fn test_sync<T: Sync>(_t: T) {}
+   |                 ^^^^ required by this bound in `test_sync`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/sync/suggest-cell.rs b/tests/ui/sync/suggest-cell.rs
new file mode 100644 (file)
index 0000000..3284eae
--- /dev/null
@@ -0,0 +1,31 @@
+fn require_sync<T: Sync>() {}
+//~^ NOTE required by this bound in `require_sync`
+//~| NOTE required by this bound in `require_sync`
+//~| NOTE required by this bound in `require_sync`
+//~| NOTE required by this bound in `require_sync`
+//~| NOTE required by a bound in `require_sync`
+//~| NOTE required by a bound in `require_sync`
+//~| NOTE required by a bound in `require_sync`
+//~| NOTE required by a bound in `require_sync`
+
+fn main() {
+    require_sync::<std::cell::Cell<()>>();
+    //~^ ERROR `Cell<()>` cannot be shared between threads safely
+    //~| NOTE `Cell<()>` cannot be shared between threads safely
+    //~| NOTE if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock`
+
+    require_sync::<std::cell::Cell<u8>>();
+    //~^ ERROR `Cell<u8>` cannot be shared between threads safely
+    //~| NOTE `Cell<u8>` cannot be shared between threads safely
+    //~| NOTE if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` or `std::sync::atomic::AtomicU8` instead
+
+    require_sync::<std::cell::Cell<i32>>();
+    //~^ ERROR `Cell<i32>` cannot be shared between threads safely
+    //~| NOTE `Cell<i32>` cannot be shared between threads safely
+    //~| NOTE if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` or `std::sync::atomic::AtomicI32` instead
+
+    require_sync::<std::cell::Cell<bool>>();
+    //~^ ERROR `Cell<bool>` cannot be shared between threads safely
+    //~| NOTE `Cell<bool>` cannot be shared between threads safely
+    //~| NOTE if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` or `std::sync::atomic::AtomicBool` instead
+}
diff --git a/tests/ui/sync/suggest-cell.stderr b/tests/ui/sync/suggest-cell.stderr
new file mode 100644 (file)
index 0000000..c232c1c
--- /dev/null
@@ -0,0 +1,59 @@
+error[E0277]: `Cell<()>` cannot be shared between threads safely
+  --> $DIR/suggest-cell.rs:12:20
+   |
+LL |     require_sync::<std::cell::Cell<()>>();
+   |                    ^^^^^^^^^^^^^^^^^^^ `Cell<()>` cannot be shared between threads safely
+   |
+   = help: the trait `Sync` is not implemented for `Cell<()>`
+   = note: if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock`
+note: required by a bound in `require_sync`
+  --> $DIR/suggest-cell.rs:1:20
+   |
+LL | fn require_sync<T: Sync>() {}
+   |                    ^^^^ required by this bound in `require_sync`
+
+error[E0277]: `Cell<u8>` cannot be shared between threads safely
+  --> $DIR/suggest-cell.rs:17:20
+   |
+LL |     require_sync::<std::cell::Cell<u8>>();
+   |                    ^^^^^^^^^^^^^^^^^^^ `Cell<u8>` cannot be shared between threads safely
+   |
+   = help: the trait `Sync` is not implemented for `Cell<u8>`
+   = note: if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` or `std::sync::atomic::AtomicU8` instead
+note: required by a bound in `require_sync`
+  --> $DIR/suggest-cell.rs:1:20
+   |
+LL | fn require_sync<T: Sync>() {}
+   |                    ^^^^ required by this bound in `require_sync`
+
+error[E0277]: `Cell<i32>` cannot be shared between threads safely
+  --> $DIR/suggest-cell.rs:22:20
+   |
+LL |     require_sync::<std::cell::Cell<i32>>();
+   |                    ^^^^^^^^^^^^^^^^^^^^ `Cell<i32>` cannot be shared between threads safely
+   |
+   = help: the trait `Sync` is not implemented for `Cell<i32>`
+   = note: if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` or `std::sync::atomic::AtomicI32` instead
+note: required by a bound in `require_sync`
+  --> $DIR/suggest-cell.rs:1:20
+   |
+LL | fn require_sync<T: Sync>() {}
+   |                    ^^^^ required by this bound in `require_sync`
+
+error[E0277]: `Cell<bool>` cannot be shared between threads safely
+  --> $DIR/suggest-cell.rs:27:20
+   |
+LL |     require_sync::<std::cell::Cell<bool>>();
+   |                    ^^^^^^^^^^^^^^^^^^^^^ `Cell<bool>` cannot be shared between threads safely
+   |
+   = help: the trait `Sync` is not implemented for `Cell<bool>`
+   = note: if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` or `std::sync::atomic::AtomicBool` instead
+note: required by a bound in `require_sync`
+  --> $DIR/suggest-cell.rs:1:20
+   |
+LL | fn require_sync<T: Sync>() {}
+   |                    ^^^^ required by this bound in `require_sync`
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/sync/suggest-once-cell.rs b/tests/ui/sync/suggest-once-cell.rs
new file mode 100644 (file)
index 0000000..82fca45
--- /dev/null
@@ -0,0 +1,12 @@
+#![feature(once_cell)]
+
+fn require_sync<T: Sync>() {}
+//~^ NOTE required by this bound in `require_sync`
+//~| NOTE required by a bound in `require_sync`
+
+fn main() {
+    require_sync::<std::cell::OnceCell<()>>();
+    //~^ ERROR `OnceCell<()>` cannot be shared between threads safely
+    //~| NOTE `OnceCell<()>` cannot be shared between threads safely
+    //~| NOTE use `std::sync::OnceLock` instead
+}
diff --git a/tests/ui/sync/suggest-once-cell.stderr b/tests/ui/sync/suggest-once-cell.stderr
new file mode 100644 (file)
index 0000000..fadf053
--- /dev/null
@@ -0,0 +1,17 @@
+error[E0277]: `OnceCell<()>` cannot be shared between threads safely
+  --> $DIR/suggest-once-cell.rs:8:20
+   |
+LL |     require_sync::<std::cell::OnceCell<()>>();
+   |                    ^^^^^^^^^^^^^^^^^^^^^^^ `OnceCell<()>` cannot be shared between threads safely
+   |
+   = help: the trait `Sync` is not implemented for `OnceCell<()>`
+   = note: if you want to do aliasing and mutation between multiple threads, use `std::sync::OnceLock` instead
+note: required by a bound in `require_sync`
+  --> $DIR/suggest-once-cell.rs:3:20
+   |
+LL | fn require_sync<T: Sync>() {}
+   |                    ^^^^ required by this bound in `require_sync`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/sync/suggest-ref-cell.rs b/tests/ui/sync/suggest-ref-cell.rs
new file mode 100644 (file)
index 0000000..6b972ae
--- /dev/null
@@ -0,0 +1,12 @@
+#![feature(once_cell)]
+
+fn require_sync<T: Sync>() {}
+//~^ NOTE required by this bound in `require_sync`
+//~| NOTE required by a bound in `require_sync`
+
+fn main() {
+    require_sync::<std::cell::RefCell<()>>();
+    //~^ ERROR `RefCell<()>` cannot be shared between threads safely
+    //~| NOTE `RefCell<()>` cannot be shared between threads safely
+    //~| NOTE use `std::sync::RwLock` instead
+}
diff --git a/tests/ui/sync/suggest-ref-cell.stderr b/tests/ui/sync/suggest-ref-cell.stderr
new file mode 100644 (file)
index 0000000..9e8b8fc
--- /dev/null
@@ -0,0 +1,17 @@
+error[E0277]: `RefCell<()>` cannot be shared between threads safely
+  --> $DIR/suggest-ref-cell.rs:8:20
+   |
+LL |     require_sync::<std::cell::RefCell<()>>();
+   |                    ^^^^^^^^^^^^^^^^^^^^^^ `RefCell<()>` cannot be shared between threads safely
+   |
+   = help: the trait `Sync` is not implemented for `RefCell<()>`
+   = note: if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` instead
+note: required by a bound in `require_sync`
+  --> $DIR/suggest-ref-cell.rs:3:20
+   |
+LL | fn require_sync<T: Sync>() {}
+   |                    ^^^^ required by this bound in `require_sync`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
index ade552c4bab41a0dc45c5c500247cce82888300d..c7af71a421438b7ac9e595ef443df5f895563bee 100644 (file)
@@ -1,6 +1,8 @@
 error[E0597]: `s` does not live long enough
   --> $DIR/check-trait-object-bounds-3.rs:15:34
    |
+LL |         let s = String::from("abcdef");
+   |             - binding `s` declared here
 LL |         z = f::<dyn X<Y = &str>>(&s);
    |             ---------------------^^-
    |             |                    |
index 5cfb64901233ea79e780e6613e3da060cdeb0581..ae70202ab7ccd5d145640988c605c6ae9e51627e 100644 (file)
@@ -1,6 +1,8 @@
 error[E0597]: `person` does not live long enough
   --> $DIR/coercion-generic-regions.rs:17:24
    |
+LL |     let person = "Fred".to_string();
+   |         ------ binding `person` declared here
 LL |     let person: &str = &person;
    |                        ^^^^^^^
    |                        |
diff --git a/tests/ui/traits/new-solver/async.fail.stderr b/tests/ui/traits/new-solver/async.fail.stderr
new file mode 100644 (file)
index 0000000..b395c23
--- /dev/null
@@ -0,0 +1,17 @@
+error[E0271]: expected `[async block@$DIR/async.rs:12:17: 12:25]` to be a future that resolves to `i32`, but it resolves to `()`
+  --> $DIR/async.rs:12:17
+   |
+LL |     needs_async(async {});
+   |     ----------- ^^^^^^^^ expected `i32`, found `()`
+   |     |
+   |     required by a bound introduced by this call
+   |
+note: required by a bound in `needs_async`
+  --> $DIR/async.rs:8:31
+   |
+LL | fn needs_async(_: impl Future<Output = i32>) {}
+   |                               ^^^^^^^^^^^^ required by this bound in `needs_async`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0271`.
diff --git a/tests/ui/traits/new-solver/async.rs b/tests/ui/traits/new-solver/async.rs
new file mode 100644 (file)
index 0000000..195cc35
--- /dev/null
@@ -0,0 +1,19 @@
+// compile-flags: -Ztrait-solver=next
+// edition: 2021
+// revisions: pass fail
+//[pass] check-pass
+
+use std::future::Future;
+
+fn needs_async(_: impl Future<Output = i32>) {}
+
+#[cfg(fail)]
+fn main() {
+    needs_async(async {});
+    //[fail]~^ ERROR to be a future that resolves to `i32`, but it resolves to `()`
+}
+
+#[cfg(pass)]
+fn main() {
+    needs_async(async { 1i32 });
+}
diff --git a/tests/ui/traits/new-solver/generator.fail.stderr b/tests/ui/traits/new-solver/generator.fail.stderr
new file mode 100644 (file)
index 0000000..d94d41e
--- /dev/null
@@ -0,0 +1,64 @@
+error[E0277]: the trait bound `[generator@$DIR/generator.rs:18:21: 18:23]: Generator<A>` is not satisfied
+  --> $DIR/generator.rs:18:21
+   |
+LL |       needs_generator(|| {
+   |  _____---------------_^
+   | |     |
+   | |     required by a bound introduced by this call
+LL | |
+LL | |
+LL | |
+LL | |         yield ();
+LL | |     });
+   | |_____^ the trait `Generator<A>` is not implemented for `[generator@$DIR/generator.rs:18:21: 18:23]`
+   |
+note: required by a bound in `needs_generator`
+  --> $DIR/generator.rs:14:28
+   |
+LL | fn needs_generator(_: impl Generator<A, Yield = B, Return = C>) {}
+   |                            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `needs_generator`
+
+error[E0271]: type mismatch resolving `<[generator@$DIR/generator.rs:18:21: 18:23] as Generator<A>>::Yield == B`
+  --> $DIR/generator.rs:18:21
+   |
+LL |       needs_generator(|| {
+   |  _____---------------_^
+   | |     |
+   | |     required by a bound introduced by this call
+LL | |
+LL | |
+LL | |
+LL | |         yield ();
+LL | |     });
+   | |_____^ types differ
+   |
+note: required by a bound in `needs_generator`
+  --> $DIR/generator.rs:14:41
+   |
+LL | fn needs_generator(_: impl Generator<A, Yield = B, Return = C>) {}
+   |                                         ^^^^^^^^^ required by this bound in `needs_generator`
+
+error[E0271]: type mismatch resolving `<[generator@$DIR/generator.rs:18:21: 18:23] as Generator<A>>::Return == C`
+  --> $DIR/generator.rs:18:21
+   |
+LL |       needs_generator(|| {
+   |  _____---------------_^
+   | |     |
+   | |     required by a bound introduced by this call
+LL | |
+LL | |
+LL | |
+LL | |         yield ();
+LL | |     });
+   | |_____^ types differ
+   |
+note: required by a bound in `needs_generator`
+  --> $DIR/generator.rs:14:52
+   |
+LL | fn needs_generator(_: impl Generator<A, Yield = B, Return = C>) {}
+   |                                                    ^^^^^^^^^^ required by this bound in `needs_generator`
+
+error: aborting due to 3 previous errors
+
+Some errors have detailed explanations: E0271, E0277.
+For more information about an error, try `rustc --explain E0271`.
diff --git a/tests/ui/traits/new-solver/generator.rs b/tests/ui/traits/new-solver/generator.rs
new file mode 100644 (file)
index 0000000..364373c
--- /dev/null
@@ -0,0 +1,32 @@
+// compile-flags: -Ztrait-solver=next
+// edition: 2021
+// revisions: pass fail
+//[pass] check-pass
+
+#![feature(generator_trait, generators)]
+
+use std::ops::Generator;
+
+struct A;
+struct B;
+struct C;
+
+fn needs_generator(_: impl Generator<A, Yield = B, Return = C>) {}
+
+#[cfg(fail)]
+fn main() {
+    needs_generator(|| {
+        //[fail]~^ ERROR Generator<A>` is not satisfied
+        //[fail]~| ERROR as Generator<A>>::Yield == B`
+        //[fail]~| ERROR as Generator<A>>::Return == C`
+        yield ();
+    });
+}
+
+#[cfg(pass)]
+fn main() {
+    needs_generator(|_: A| {
+        let _: A = yield B;
+        C
+    })
+}
diff --git a/tests/ui/traits/new-solver/pointee.rs b/tests/ui/traits/new-solver/pointee.rs
new file mode 100644 (file)
index 0000000..fa6ee2e
--- /dev/null
@@ -0,0 +1,23 @@
+// compile-flags: -Ztrait-solver=next
+// check-pass
+#![feature(ptr_metadata)]
+
+use std::ptr::{DynMetadata, Pointee};
+
+trait Trait<U> {}
+struct MyDst<T: ?Sized>(T);
+
+fn works<T>() {
+    let _: <T as Pointee>::Metadata = ();
+    let _: <[T] as Pointee>::Metadata = 1_usize;
+    let _: <str as Pointee>::Metadata = 1_usize;
+    let _: <dyn Trait<T> as Pointee>::Metadata = give::<DynMetadata<dyn Trait<T>>>();
+    let _: <MyDst<T> as Pointee>::Metadata = ();
+    let _: <((((([u8],),),),),) as Pointee>::Metadata = 1_usize;
+}
+
+fn give<U>() -> U {
+    loop {}
+}
+
+fn main() {}
index c4f8294e26356a81f183af1fbb8b991eca42cc75..89360c44e78b45de94145848ed48cdebd67e0b38 100644 (file)
@@ -1,6 +1,9 @@
 error[E0505]: cannot move out of `v` because it is borrowed
   --> $DIR/issue-97381.rs:26:14
    |
+LL |     let v = [1, 2, 3]
+   |         - binding `v` declared here
+...
 LL |     let el = &v[0];
    |               - borrow of `v` occurs here
 LL |
index ea079e30d9c395858450c640a2bf29bc2da0f22d..28941cb0a9e4033296ed05666e0a03684d30630b 100644 (file)
@@ -4,6 +4,7 @@ error[E0597]: `my_string` does not live long enough
 LL |         let result: Result<(), &str> = try {
    |             ------ borrow later stored here
 LL |             let my_string = String::from("");
+   |                 --------- binding `my_string` declared here
 LL |             let my_str: & str = & my_string;
    |                                 ^^^^^^^^^^^ borrowed value does not live long enough
 ...
@@ -14,10 +15,10 @@ error[E0506]: cannot assign to `i` because it is borrowed
   --> $DIR/try-block-bad-lifetime.rs:29:13
    |
 LL |         let k = &mut i;
-   |                 ------ borrow of `i` occurs here
+   |                 ------ `i` is borrowed here
 ...
 LL |             i = 10;
-   |             ^^^^^^ assignment to borrowed `i` occurs here
+   |             ^^^^^^ `i` is assigned to here but it was already borrowed
 LL |         };
 LL |         ::std::mem::drop(k);
    |                          - borrow later used here
@@ -38,10 +39,10 @@ error[E0506]: cannot assign to `i` because it is borrowed
   --> $DIR/try-block-bad-lifetime.rs:32:9
    |
 LL |         let k = &mut i;
-   |                 ------ borrow of `i` occurs here
+   |                 ------ `i` is borrowed here
 ...
 LL |         i = 40;
-   |         ^^^^^^ assignment to borrowed `i` occurs here
+   |         ^^^^^^ `i` is assigned to here but it was already borrowed
 LL |
 LL |         let i_ptr = if let Err(i_ptr) = j { i_ptr } else { panic ! ("") };
    |                                         - borrow later used here
index f738b03eed6b8441cba5d88252b8dd6ddb39a1cb..71c7e460c3992cc8a2018505a5adf992738dfab4 100644 (file)
@@ -2,10 +2,10 @@ error[E0506]: cannot assign to `i` because it is borrowed
   --> $DIR/try-block-maybe-bad-lifetime.rs:17:9
    |
 LL |             &i
-   |             -- borrow of `i` occurs here
+   |             -- `i` is borrowed here
 LL |         };
 LL |         i = 0;
-   |         ^^^^^ assignment to borrowed `i` occurs here
+   |         ^^^^^ `i` is assigned to here but it was already borrowed
 LL |         let _ = i;
 LL |         do_something_with(x);
    |                           - borrow later used here
@@ -32,10 +32,10 @@ error[E0506]: cannot assign to `i` because it is borrowed
   --> $DIR/try-block-maybe-bad-lifetime.rs:40:9
    |
 LL |             j = &i;
-   |                 -- borrow of `i` occurs here
+   |                 -- `i` is borrowed here
 LL |         };
 LL |         i = 0;
-   |         ^^^^^ assignment to borrowed `i` occurs here
+   |         ^^^^^ `i` is assigned to here but it was already borrowed
 LL |         let _ = i;
 LL |         do_something_with(j);
    |                           - borrow later used here
index 83d22161e4e75617fb3845576e8b6843d0eb966a..eeb5dca07f06a4bd86bc34fc0f2e2e26e5b8a7db 100644 (file)
@@ -8,7 +8,7 @@
 fn f<'a: 'static>(t: &'a str) -> X<'a> {
     //~^ WARNING unnecessary lifetime parameter
     t
-    //~^ ERROR non-defining opaque type use
+    //~^ ERROR expected generic lifetime parameter, found `'static`
 }
 
 fn extend_lt<'a>(o: &'a str) -> &'static str {
index 920eef11da4b993dcdf66fb168602371b8145781..94882597a62e6fd823ceb778ca1e5c18bebe16c8 100644 (file)
@@ -6,7 +6,7 @@ LL | fn f<'a: 'static>(t: &'a str) -> X<'a> {
    |
    = help: you can use the `'static` lifetime directly, in place of `'a`
 
-error: non-defining opaque type use in defining scope
+error[E0792]: expected generic lifetime parameter, found `'static`
   --> $DIR/bounds-are-checked.rs:10:5
    |
 LL | type X<'a> = impl Into<&'static str> + From<&'a str>;
@@ -17,3 +17,4 @@ LL |     t
 
 error: aborting due to previous error; 1 warning emitted
 
+For more information about this error, try `rustc --explain E0792`.
index f5045d382aac4ed63c4be46e727c657ea6444a1c..e7b8567b9a217d7e629343116d52655ac114e04a 100644 (file)
@@ -19,7 +19,7 @@ fn concrete_ty() -> OneTy<u32> {
 
 fn concrete_lifetime() -> OneLifetime<'static> {
     6u32
-    //~^ ERROR non-defining opaque type use in defining scope
+    //~^ ERROR expected generic lifetime parameter, found `'static`
 }
 
 fn concrete_const() -> OneConst<{ 123 }> {
index 564648630b16122127ce6a1c026785740f68c118..966fe823f024dd99e4f3e6d1e70688ffb674aa97 100644 (file)
@@ -7,7 +7,7 @@ LL | type OneTy<T> = impl Debug;
 LL |     5u32
    |     ^^^^
 
-error: non-defining opaque type use in defining scope
+error[E0792]: expected generic lifetime parameter, found `'static`
   --> $DIR/generic_nondefining_use.rs:21:5
    |
 LL | type OneLifetime<'a> = impl Debug;
diff --git a/tests/ui/type/type-check/coerce-result-return-value-2.rs b/tests/ui/type/type-check/coerce-result-return-value-2.rs
new file mode 100644 (file)
index 0000000..23bafa6
--- /dev/null
@@ -0,0 +1,24 @@
+struct A;
+struct B;
+impl From<A> for B {
+    fn from(_: A) -> Self { B }
+}
+fn foo4(x: Result<(), A>) -> Result<(), B> {
+    match true {
+        true => x, //~ ERROR mismatched types
+        false => x,
+    }
+}
+fn foo5(x: Result<(), A>) -> Result<(), B> {
+    match true {
+        true => return x, //~ ERROR mismatched types
+        false => return x,
+    }
+}
+fn main() {
+    let _ = foo4(Ok(()));
+    let _ = foo5(Ok(()));
+    let _: Result<(), B> = { //~ ERROR mismatched types
+        Err(A);
+    };
+}
diff --git a/tests/ui/type/type-check/coerce-result-return-value-2.stderr b/tests/ui/type/type-check/coerce-result-return-value-2.stderr
new file mode 100644 (file)
index 0000000..5992162
--- /dev/null
@@ -0,0 +1,47 @@
+error[E0308]: mismatched types
+  --> $DIR/coerce-result-return-value-2.rs:8:17
+   |
+LL | fn foo4(x: Result<(), A>) -> Result<(), B> {
+   |                              ------------- expected `Result<(), B>` because of return type
+LL |     match true {
+LL |         true => x,
+   |                 ^ expected struct `B`, found struct `A`
+   |
+   = note: expected enum `Result<_, B>`
+              found enum `Result<_, A>`
+help: use `?` to coerce and return an appropriate `Err`, and wrap the resulting value in `Ok` so the expression remains of type `Result`
+   |
+LL |         true => Ok(x?),
+   |                 +++ ++
+
+error[E0308]: mismatched types
+  --> $DIR/coerce-result-return-value-2.rs:14:24
+   |
+LL | fn foo5(x: Result<(), A>) -> Result<(), B> {
+   |                              ------------- expected `Result<(), B>` because of return type
+LL |     match true {
+LL |         true => return x,
+   |                        ^ expected struct `B`, found struct `A`
+   |
+   = note: expected enum `Result<_, B>`
+              found enum `Result<_, A>`
+help: use `?` to coerce and return an appropriate `Err`, and wrap the resulting value in `Ok` so the expression remains of type `Result`
+   |
+LL |         true => return Ok(x?),
+   |                        +++ ++
+
+error[E0308]: mismatched types
+  --> $DIR/coerce-result-return-value-2.rs:21:28
+   |
+LL |       let _: Result<(), B> = {
+   |  ____________________________^
+LL | |         Err(A);
+LL | |     };
+   | |_____^ expected enum `Result`, found `()`
+   |
+   = note:   expected enum `Result<(), B>`
+           found unit type `()`
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/type/type-check/coerce-result-return-value.fixed b/tests/ui/type/type-check/coerce-result-return-value.fixed
new file mode 100644 (file)
index 0000000..8a05407
--- /dev/null
@@ -0,0 +1,24 @@
+// run-rustfix
+struct A;
+struct B;
+impl From<A> for B {
+    fn from(_: A) -> Self { B }
+}
+fn foo1(x: Result<(), A>) -> Result<(), B> {
+    Ok(x?) //~ ERROR mismatched types
+}
+fn foo2(x: Result<(), A>) -> Result<(), B> {
+    return Ok(x?); //~ ERROR mismatched types
+}
+fn foo3(x: Result<(), A>) -> Result<(), B> {
+    if true {
+        Ok(x?) //~ ERROR mismatched types
+    } else {
+        Ok(x?) //~ ERROR mismatched types
+    }
+}
+fn main() {
+    let _ = foo1(Ok(()));
+    let _ = foo2(Ok(()));
+    let _ = foo3(Ok(()));
+}
diff --git a/tests/ui/type/type-check/coerce-result-return-value.rs b/tests/ui/type/type-check/coerce-result-return-value.rs
new file mode 100644 (file)
index 0000000..442203a
--- /dev/null
@@ -0,0 +1,24 @@
+// run-rustfix
+struct A;
+struct B;
+impl From<A> for B {
+    fn from(_: A) -> Self { B }
+}
+fn foo1(x: Result<(), A>) -> Result<(), B> {
+    x //~ ERROR mismatched types
+}
+fn foo2(x: Result<(), A>) -> Result<(), B> {
+    return x; //~ ERROR mismatched types
+}
+fn foo3(x: Result<(), A>) -> Result<(), B> {
+    if true {
+        x //~ ERROR mismatched types
+    } else {
+        x //~ ERROR mismatched types
+    }
+}
+fn main() {
+    let _ = foo1(Ok(()));
+    let _ = foo2(Ok(()));
+    let _ = foo3(Ok(()));
+}
diff --git a/tests/ui/type/type-check/coerce-result-return-value.stderr b/tests/ui/type/type-check/coerce-result-return-value.stderr
new file mode 100644 (file)
index 0000000..5501535
--- /dev/null
@@ -0,0 +1,65 @@
+error[E0308]: mismatched types
+  --> $DIR/coerce-result-return-value.rs:8:5
+   |
+LL | fn foo1(x: Result<(), A>) -> Result<(), B> {
+   |                              ------------- expected `Result<(), B>` because of return type
+LL |     x
+   |     ^ expected struct `B`, found struct `A`
+   |
+   = note: expected enum `Result<_, B>`
+              found enum `Result<_, A>`
+help: use `?` to coerce and return an appropriate `Err`, and wrap the resulting value in `Ok` so the expression remains of type `Result`
+   |
+LL |     Ok(x?)
+   |     +++ ++
+
+error[E0308]: mismatched types
+  --> $DIR/coerce-result-return-value.rs:11:12
+   |
+LL | fn foo2(x: Result<(), A>) -> Result<(), B> {
+   |                              ------------- expected `Result<(), B>` because of return type
+LL |     return x;
+   |            ^ expected struct `B`, found struct `A`
+   |
+   = note: expected enum `Result<_, B>`
+              found enum `Result<_, A>`
+help: use `?` to coerce and return an appropriate `Err`, and wrap the resulting value in `Ok` so the expression remains of type `Result`
+   |
+LL |     return Ok(x?);
+   |            +++ ++
+
+error[E0308]: mismatched types
+  --> $DIR/coerce-result-return-value.rs:15:9
+   |
+LL | fn foo3(x: Result<(), A>) -> Result<(), B> {
+   |                              ------------- expected `Result<(), B>` because of return type
+LL |     if true {
+LL |         x
+   |         ^ expected struct `B`, found struct `A`
+   |
+   = note: expected enum `Result<_, B>`
+              found enum `Result<_, A>`
+help: use `?` to coerce and return an appropriate `Err`, and wrap the resulting value in `Ok` so the expression remains of type `Result`
+   |
+LL |         Ok(x?)
+   |         +++ ++
+
+error[E0308]: mismatched types
+  --> $DIR/coerce-result-return-value.rs:17:9
+   |
+LL | fn foo3(x: Result<(), A>) -> Result<(), B> {
+   |                              ------------- expected `Result<(), B>` because of return type
+...
+LL |         x
+   |         ^ expected struct `B`, found struct `A`
+   |
+   = note: expected enum `Result<_, B>`
+              found enum `Result<_, A>`
+help: use `?` to coerce and return an appropriate `Err`, and wrap the resulting value in `Ok` so the expression remains of type `Result`
+   |
+LL |         Ok(x?)
+   |         +++ ++
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/typeck/bad-type-in-vec-push.rs b/tests/ui/typeck/bad-type-in-vec-push.rs
new file mode 100644 (file)
index 0000000..a807f03
--- /dev/null
@@ -0,0 +1,20 @@
+// The error message here still is pretty confusing.
+
+fn main() {
+    let mut result = vec![1];
+    // The type of `result` is constrained to be `Vec<{integer}>` here.
+    // But the logic we use to find what expression constrains a type
+    // is not sophisticated enough to know this.
+
+    let mut vector = Vec::new();
+    vector.sort();
+    result.push(vector);
+    //~^ ERROR mismatched types
+    // So it thinks that the type of `result` is constrained here.
+}
+
+fn example2() {
+    let mut x = vec![1];
+    x.push("");
+    //~^ ERROR mismatched types
+}
diff --git a/tests/ui/typeck/bad-type-in-vec-push.stderr b/tests/ui/typeck/bad-type-in-vec-push.stderr
new file mode 100644 (file)
index 0000000..e4c99ec
--- /dev/null
@@ -0,0 +1,29 @@
+error[E0308]: mismatched types
+  --> $DIR/bad-type-in-vec-push.rs:11:17
+   |
+LL |     vector.sort();
+   |     ------ here the type of `vector` is inferred to be `Vec<_>`
+LL |     result.push(vector);
+   |            ---- ^^^^^^ expected integer, found struct `Vec`
+   |            |
+   |            arguments to this method are incorrect
+   |
+   = note: expected type `{integer}`
+            found struct `Vec<_>`
+note: associated function defined here
+  --> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
+
+error[E0308]: mismatched types
+  --> $DIR/bad-type-in-vec-push.rs:18:12
+   |
+LL |     x.push("");
+   |       ---- ^^ expected integer, found `&str`
+   |       |
+   |       arguments to this method are incorrect
+   |
+note: associated function defined here
+  --> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
index 21d6b4fde7e905f94f49affc7d58a1770be38199..98fe97c5c1814e5051bb02c8ae49a3f1e21253e1 100644 (file)
@@ -4,7 +4,7 @@ error[E0503]: cannot use `x` because it was mutably borrowed
 LL |     let f = || x += 1;
    |             -- - borrow occurs due to use of `x` in closure
    |             |
-   |             borrow of `x` occurs here
+   |             `x` is borrowed here
 LL |     let _y = x;
    |              ^ use of borrowed `x`
 LL |     f;
index cbdb4dd0fb5c8cd939aa1f7f68e8ab7960899f50..23aa18d7156ac9509033767b276349fd76ef8981 100644 (file)
@@ -16,14 +16,14 @@ error[E0506]: cannot assign to `factorial` because it is borrowed
   --> $DIR/unboxed-closures-failed-recursive-fn-1.rs:20:5
    |
 LL |     let f = |x: u32| -> u32 {
-   |             --------------- borrow of `factorial` occurs here
+   |             --------------- `factorial` is borrowed here
 LL |         let g = factorial.as_ref().unwrap();
    |                 --------- borrow occurs due to use in closure
 ...
 LL |     factorial = Some(Box::new(f));
    |     ^^^^^^^^^
    |     |
-   |     assignment to borrowed `factorial` occurs here
+   |     `factorial` is assigned to here but it was already borrowed
    |     borrow later used here
 
 error[E0597]: `factorial` does not live long enough
@@ -47,12 +47,12 @@ LL |     let mut factorial: Option<Box<dyn Fn(u32) -> u32 + 'static>> = None;
    |                        ----------------------------------------- type annotation requires that `factorial` is borrowed for `'static`
 LL |
 LL |     let f = |x: u32| -> u32 {
-   |             --------------- borrow of `factorial` occurs here
+   |             --------------- `factorial` is borrowed here
 LL |         let g = factorial.as_ref().unwrap();
    |                 --------- borrow occurs due to use in closure
 ...
 LL |     factorial = Some(Box::new(f));
-   |     ^^^^^^^^^ assignment to borrowed `factorial` occurs here
+   |     ^^^^^^^^^ `factorial` is assigned to here but it was already borrowed
 
 error: aborting due to 4 previous errors
 
index 2a3ca14433f62ffeaec52fb189a016064eda8d35..e47785c465ac6a8614c1fe21eaabd9a9a1e64cc3 100644 (file)
@@ -23,6 +23,8 @@ LL | fn move_then_borrow<T: Not<Output=T> + Clone + Copy>(x: T) {
 error[E0505]: cannot move out of `x` because it is borrowed
   --> $DIR/unop-move-semantics.rs:15:6
    |
+LL | fn move_borrowed<T: Not<Output=T>>(x: T, mut y: T) {
+   |                                    - binding `x` declared here
 LL |     let m = &x;
    |             -- borrow of `x` occurs here
 ...
@@ -35,6 +37,9 @@ LL |     use_mut(n); use_imm(m);
 error[E0505]: cannot move out of `y` because it is borrowed
   --> $DIR/unop-move-semantics.rs:17:6
    |
+LL | fn move_borrowed<T: Not<Output=T>>(x: T, mut y: T) {
+   |                                          ----- binding `y` declared here
+LL |     let m = &x;
 LL |     let n = &mut y;
    |             ------ borrow of `y` occurs here
 ...
index 008e2a002bbb06829e637a8f8c88b1b048822108..258f67db5ce4b50a9185ac46ad3e9613ed2df121 100644 (file)
@@ -1,6 +1,8 @@
 error[E0505]: cannot move out of `a` because it is borrowed
   --> $DIR/variance-issue-20533.rs:28:14
    |
+LL |         let a = AffineU32(1);
+   |             - binding `a` declared here
 LL |         let x = foo(&a);
    |                     -- borrow of `a` occurs here
 LL |         drop(a);
@@ -11,6 +13,8 @@ LL |         drop(x);
 error[E0505]: cannot move out of `a` because it is borrowed
   --> $DIR/variance-issue-20533.rs:34:14
    |
+LL |         let a = AffineU32(1);
+   |             - binding `a` declared here
 LL |         let x = bar(&a);
    |                     -- borrow of `a` occurs here
 LL |         drop(a);
@@ -21,6 +25,8 @@ LL |         drop(x);
 error[E0505]: cannot move out of `a` because it is borrowed
   --> $DIR/variance-issue-20533.rs:40:14
    |
+LL |         let a = AffineU32(1);
+   |             - binding `a` declared here
 LL |         let x = baz(&a);
    |                     -- borrow of `a` occurs here
 LL |         drop(a);
index 16a3132151374d31dda0f22a0e822163a41e477b..79958729fc521ed1ada06422e092a769384d2377 100644 (file)
@@ -456,6 +456,9 @@ These commits modify **compiler targets**.
 (See the [Target Tier Policy](https://doc.rust-lang.org/nightly/rustc/target-tier-policy.html).)
 """
 
+[mentions."src/doc/style-guide"]
+cc = ["@rust-lang/style"]
+
 [assign]
 warn_non_default_branch = true
 contributing_url = "https://rustc-dev-guide.rust-lang.org/contributing.html"
@@ -560,6 +563,12 @@ ast_lowering = [
 fallback = [
     "@Mark-Simulacrum"
 ]
+style-team = [
+    "@calebcartwright",
+    "@compiler-errors",
+    "@joshtriplett",
+    "@yaahc",
+]
 
 [assign.owners]
 "/.github/workflows" =                       ["infra-ci"]
@@ -604,6 +613,7 @@ fallback = [
 "/src/doc/rust-by-example" =                 ["@ehuss"]
 "/src/doc/rustc-dev-guide" =                 ["@ehuss"]
 "/src/doc/rustdoc" =                         ["rustdoc"]
+"/src/doc/style-guide" =                     ["style-team"]
 "/src/etc" =                                 ["@Mark-Simulacrum"]
 "/src/librustdoc" =                          ["rustdoc"]
 "/src/llvm-project" =                        ["@cuviper"]